From bc50af15a28d5995fa2b3f4770dc05828263ae52 Mon Sep 17 00:00:00 2001 From: Wez <wez@chromium.org> Date: Mon, 30 Jul 2018 15:50:17 -0700 Subject: [PATCH 001/401] Migrate from ScopedZxHandle to libzx containers. Bug: chromium:852541 Change-Id: Ie05c70f249e6f843183a02ec61fd09f6a0607598 Reviewed-on: https://chromium-review.googlesource.com/1148923 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Wez <wez@chromium.org> --- client/BUILD.gn | 9 +- client/crashpad_client_fuchsia.cc | 19 +-- handler/BUILD.gn | 4 + .../fuchsia/crash_report_exception_handler.cc | 45 ++--- .../fuchsia/crash_report_exception_handler.h | 5 +- handler/fuchsia/exception_handler_server.cc | 10 +- handler/fuchsia/exception_handler_server.h | 11 +- handler/handler_main.cc | 5 +- snapshot/crashpad_info_client_options_test.cc | 4 +- snapshot/elf/elf_image_reader_test.cc | 11 +- snapshot/fuchsia/memory_map_fuchsia.cc | 15 +- snapshot/fuchsia/memory_map_fuchsia.h | 3 +- snapshot/fuchsia/process_reader_fuchsia.cc | 42 ++--- snapshot/fuchsia/process_reader_fuchsia.h | 5 +- .../fuchsia/process_reader_fuchsia_test.cc | 8 +- snapshot/fuchsia/process_snapshot_fuchsia.cc | 6 +- snapshot/fuchsia/process_snapshot_fuchsia.h | 5 +- test/BUILD.gn | 11 +- test/multiprocess_exec_fuchsia.cc | 26 ++- test/process_type.cc | 4 +- test/process_type.h | 4 +- third_party/fuchsia/BUILD.gn | 82 ++++++++++ tools/generate_dump.cc | 11 +- util/BUILD.gn | 4 + util/fuchsia/koid_utilities.cc | 154 +++++++++++------- util/fuchsia/koid_utilities.h | 34 ++-- util/fuchsia/scoped_task_suspend.cc | 53 ++---- util/fuchsia/scoped_task_suspend.h | 14 +- util/process/process_memory_fuchsia.cc | 13 +- util/process/process_memory_fuchsia.h | 9 +- util/process/process_memory_range_test.cc | 4 +- 31 files changed, 364 insertions(+), 266 deletions(-) create mode 100644 third_party/fuchsia/BUILD.gn diff --git a/client/BUILD.gn b/client/BUILD.gn index a074b503..a82a8dd4 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -88,10 +88,11 @@ static_library("client") { cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union } - if (crashpad_is_fuchsia && crashpad_is_in_fuchsia) { - deps += [ - "//zircon/public/lib/fdio", - ] + if (crashpad_is_fuchsia) { + deps += [ "../third_party/fuchsia:zx" ] + if (crashpad_is_in_fuchsia) { + deps += [ "//zircon/public/lib/fdio" ] + } } } diff --git a/client/crashpad_client_fuchsia.cc b/client/crashpad_client_fuchsia.cc index 0d1b65bf..0eba01d6 100644 --- a/client/crashpad_client_fuchsia.cc +++ b/client/crashpad_client_fuchsia.cc @@ -15,11 +15,12 @@ #include "client/crashpad_client.h" #include <lib/fdio/spawn.h> -#include <zircon/process.h> +#include <lib/zx/job.h> +#include <lib/zx/port.h> +#include <lib/zx/process.h> #include <zircon/processargs.h> #include "base/fuchsia/fuchsia_logging.h" -#include "base/fuchsia/scoped_zx_handle.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "client/client_argv_handling.h" @@ -43,16 +44,15 @@ bool CrashpadClient::StartHandler( DCHECK_EQ(restartable, false); // Not used on Fuchsia. DCHECK_EQ(asynchronous_start, false); // Not used on Fuchsia. - zx_handle_t exception_port_raw; - zx_status_t status = zx_port_create(0, &exception_port_raw); + zx::port exception_port; + zx_status_t status = zx::port::create(0, &exception_port); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_port_create"; return false; } - base::ScopedZxHandle exception_port(exception_port_raw); - status = zx_task_bind_exception_port( - zx_job_default(), exception_port.get(), kSystemExceptionPortKey, 0); + status = zx::job::default_job()->bind_exception_port( + exception_port, kSystemExceptionPortKey, 0); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_task_bind_exception_port"; return false; @@ -88,7 +88,7 @@ bool CrashpadClient::StartHandler( actions[1].h.handle = exception_port.release(); char error_message[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; - zx_handle_t child_raw; + zx::process child; // TODO(scottmg): https://crashpad.chromium.org/bug/196, FDIO_SPAWN_CLONE_ALL // is useful during bringup, but should probably be made minimal for real // usage. @@ -99,9 +99,8 @@ bool CrashpadClient::StartHandler( nullptr, kActionCount, actions, - &child_raw, + child.reset_and_get_address(), error_message); - base::ScopedZxHandle child(child_raw); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "fdio_spawn_etc: " << error_message; return false; diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 2eae30b5..93fd540a 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -80,6 +80,10 @@ static_library("handler") { if (crashpad_is_win) { cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union } + + if (crashpad_is_fuchsia) { + deps += [ "../third_party/fuchsia:zx" ] + } } source_set("handler_test") { diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index 1da09851..3305fef6 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -14,6 +14,7 @@ #include "handler/fuchsia/crash_report_exception_handler.h" +#include <lib/zx/thread.h> #include <zircon/syscalls/exception.h> #include "base/fuchsia/fuchsia_logging.h" @@ -22,28 +23,28 @@ #include "minidump/minidump_user_extension_stream_data_source.h" #include "snapshot/fuchsia/process_snapshot_fuchsia.h" #include "util/fuchsia/koid_utilities.h" -#include "util/fuchsia/scoped_task_suspend.h" namespace crashpad { namespace { -struct ScopedZxTaskResumeAfterException { - ScopedZxTaskResumeAfterException(zx_handle_t thread) : thread_(thread) {} - ~ScopedZxTaskResumeAfterException() { - DCHECK_NE(thread_, ZX_HANDLE_INVALID); +class ScopedThreadResumeAfterException { + public: + ScopedThreadResumeAfterException(const zx::thread& thread) + : thread_(thread) {} + ~ScopedThreadResumeAfterException() { + DCHECK(thread_->is_valid()); // Resuming with ZX_RESUME_TRY_NEXT chains to the next handler. In normal // operation, there won't be another beyond this one, which will result in // the kernel terminating the process. zx_status_t status = - zx_task_resume(thread_, ZX_RESUME_EXCEPTION | ZX_RESUME_TRY_NEXT); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_task_resume"; - } + thread_->resume(ZX_RESUME_EXCEPTION | ZX_RESUME_TRY_NEXT); + ZX_LOG_IF(ERROR, status != ZX_OK, status) << "zx_task_resume"; } private: - zx_handle_t thread_; // weak + zx::unowned_thread thread_; + DISALLOW_COPY_AND_ASSIGN(ScopedThreadResumeAfterException); }; } // namespace @@ -67,27 +68,28 @@ bool CrashReportExceptionHandler::HandleException(uint64_t process_id, // TODO(scottmg): This function needs to be instrumented with metrics calls, // https://crashpad.chromium.org/bug/230. - base::ScopedZxHandle process(GetProcessFromKoid(process_id)); + zx::process process(GetProcessFromKoid(process_id)); if (!process.is_valid()) { // There's no way to zx_task_resume() the thread if the process retrieval // fails. Assume that the process has been already killed, and bail. return false; } - base::ScopedZxHandle thread(GetChildHandleByKoid(process.get(), thread_id)); + zx::thread thread(GetThreadHandleByKoid(process, thread_id)); if (!thread.is_valid()) { return false; } - return HandleExceptionHandles(process.get(), thread.get()); + return HandleExceptionHandles(process, thread); } -bool CrashReportExceptionHandler::HandleExceptionHandles(zx_handle_t process, - zx_handle_t thread) { +bool CrashReportExceptionHandler::HandleExceptionHandles( + const zx::process& process, + const zx::thread& thread) { // Now that the thread has been successfully retrieved, it is possible to // correctly call zx_task_resume() to continue exception processing, even if // something else during this function fails. - ScopedZxTaskResumeAfterException resume(thread); + ScopedThreadResumeAfterException resume(thread); ProcessSnapshotFuchsia process_snapshot; if (!process_snapshot.Initialize(process)) { @@ -99,12 +101,11 @@ bool CrashReportExceptionHandler::HandleExceptionHandles(zx_handle_t process, if (client_options.crashpad_handler_behavior != TriState::kDisabled) { zx_exception_report_t report; - zx_status_t status = zx_object_get_info(thread, - ZX_INFO_THREAD_EXCEPTION_REPORT, - &report, - sizeof(report), - nullptr, - nullptr); + zx_status_t status = thread.get_info(ZX_INFO_THREAD_EXCEPTION_REPORT, + &report, + sizeof(report), + nullptr, + nullptr); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_object_get_info ZX_INFO_THREAD_EXCEPTION_REPORT"; diff --git a/handler/fuchsia/crash_report_exception_handler.h b/handler/fuchsia/crash_report_exception_handler.h index 5043d7e9..8eacc11f 100644 --- a/handler/fuchsia/crash_report_exception_handler.h +++ b/handler/fuchsia/crash_report_exception_handler.h @@ -15,6 +15,8 @@ #ifndef CRASHPAD_HANDLER_FUCHSIA_CRASH_REPORT_EXCEPTION_HANDLER_H_ #define CRASHPAD_HANDLER_FUCHSIA_CRASH_REPORT_EXCEPTION_HANDLER_H_ +#include <lib/zx/process.h> +#include <lib/zx/thread.h> #include <stdint.h> #include <zircon/types.h> @@ -88,7 +90,8 @@ class CrashReportExceptionHandler { //! \param[in] thread The handle to the thread of \a process which sustained //! the exception. //! \return `true` on success, or `false` with an error logged. - bool HandleExceptionHandles(zx_handle_t process, zx_handle_t thread); + bool HandleExceptionHandles(const zx::process& process, + const zx::thread& thread); private: CrashReportDatabase* database_; // weak diff --git a/handler/fuchsia/exception_handler_server.cc b/handler/fuchsia/exception_handler_server.cc index 63153d28..1b2c829f 100644 --- a/handler/fuchsia/exception_handler_server.cc +++ b/handler/fuchsia/exception_handler_server.cc @@ -14,7 +14,7 @@ #include "handler/fuchsia/exception_handler_server.h" -#include <zircon/syscalls/exception.h> +#include <lib/zx/time.h> #include <zircon/syscalls/port.h> #include <utility> @@ -26,9 +26,8 @@ namespace crashpad { -ExceptionHandlerServer::ExceptionHandlerServer( - base::ScopedZxHandle root_job, - base::ScopedZxHandle exception_port) +ExceptionHandlerServer::ExceptionHandlerServer(zx::job root_job, + zx::port exception_port) : root_job_(std::move(root_job)), exception_port_(std::move(exception_port)) {} @@ -37,8 +36,7 @@ ExceptionHandlerServer::~ExceptionHandlerServer() = default; void ExceptionHandlerServer::Run(CrashReportExceptionHandler* handler) { while (true) { zx_port_packet_t packet; - zx_status_t status = - zx_port_wait(exception_port_.get(), ZX_TIME_INFINITE, &packet); + zx_status_t status = exception_port_.wait(zx::time::infinite(), &packet); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_port_wait, aborting"; return; diff --git a/handler/fuchsia/exception_handler_server.h b/handler/fuchsia/exception_handler_server.h index 184d1489..1832f02c 100644 --- a/handler/fuchsia/exception_handler_server.h +++ b/handler/fuchsia/exception_handler_server.h @@ -15,8 +15,10 @@ #ifndef CRASHPAD_HANDLER_FUCHSIA_EXCEPTION_HANDLER_SERVER_H_ #define CRASHPAD_HANDLER_FUCHSIA_EXCEPTION_HANDLER_SERVER_H_ +#include <lib/zx/job.h> +#include <lib/zx/port.h> + #include "base/macros.h" -#include "base/fuchsia/scoped_zx_handle.h" namespace crashpad { @@ -33,8 +35,7 @@ class ExceptionHandlerServer { //! port of this job. //! \param[in] exception_port The exception port that this server will //! monitor. - ExceptionHandlerServer(base::ScopedZxHandle root_job, - base::ScopedZxHandle exception_port); + ExceptionHandlerServer(zx::job root_job, zx::port exception_port); ~ExceptionHandlerServer(); //! \brief Runs the exception-handling server. @@ -44,8 +45,8 @@ class ExceptionHandlerServer { void Run(CrashReportExceptionHandler* handler); private: - base::ScopedZxHandle root_job_; - base::ScopedZxHandle exception_port_; + zx::job root_job_; + zx::port exception_port_; DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServer); }; diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 412ee112..b3e0a68a 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -943,14 +943,13 @@ int HandlerMain(int argc, // owns them in this process. There is currently no "connect-later" mode on // Fuchsia, all the binding must be done by the client before starting // crashpad_handler. - base::ScopedZxHandle root_job(zx_take_startup_handle(PA_HND(PA_USER0, 0))); + zx::job root_job(zx_take_startup_handle(PA_HND(PA_USER0, 0))); if (!root_job.is_valid()) { LOG(ERROR) << "no process handle passed in startup handle 0"; return EXIT_FAILURE; } - base::ScopedZxHandle exception_port( - zx_take_startup_handle(PA_HND(PA_USER0, 1))); + zx::port exception_port(zx_take_startup_handle(PA_HND(PA_USER0, 1))); if (!exception_port.is_valid()) { LOG(ERROR) << "no exception port handle passed in startup handle 1"; return EXIT_FAILURE; diff --git a/snapshot/crashpad_info_client_options_test.cc b/snapshot/crashpad_info_client_options_test.cc index 1fe38acf..d1c5f9d3 100644 --- a/snapshot/crashpad_info_client_options_test.cc +++ b/snapshot/crashpad_info_client_options_test.cc @@ -32,7 +32,7 @@ #include <windows.h> #include "snapshot/win/process_snapshot_win.h" #elif defined(OS_FUCHSIA) -#include <zircon/process.h> +#include <lib/zx/process.h> #include "snapshot/fuchsia/process_snapshot_fuchsia.h" #endif @@ -86,7 +86,7 @@ CrashpadInfoClientOptions SelfProcessSnapshotAndGetCrashpadOptions() { GetCurrentProcess(), ProcessSuspensionState::kRunning, 0, 0)); #elif defined(OS_FUCHSIA) ProcessSnapshotFuchsia process_snapshot; - EXPECT_TRUE(process_snapshot.Initialize(zx_process_self())); + EXPECT_TRUE(process_snapshot.Initialize(*zx::process::self())); #else #error Port. #endif // OS_MACOSX diff --git a/snapshot/elf/elf_image_reader_test.cc b/snapshot/elf/elf_image_reader_test.cc index 11fb1feb..6d88d817 100644 --- a/snapshot/elf/elf_image_reader_test.cc +++ b/snapshot/elf/elf_image_reader_test.cc @@ -32,8 +32,7 @@ #include "util/process/process_memory_native.h" #if defined(OS_FUCHSIA) - -#include <zircon/syscalls.h> +#include <lib/zx/process.h> #include "base/fuchsia/fuchsia_logging.h" @@ -61,14 +60,12 @@ namespace { #if defined(OS_FUCHSIA) -void LocateExecutable(ProcessType process, +void LocateExecutable(const ProcessType& process, ProcessMemory* memory, VMAddress* elf_address) { uintptr_t debug_address; - zx_status_t status = zx_object_get_property(process, - ZX_PROP_PROCESS_DEBUG_ADDR, - &debug_address, - sizeof(debug_address)); + zx_status_t status = process->get_property( + ZX_PROP_PROCESS_DEBUG_ADDR, &debug_address, sizeof(debug_address)); ASSERT_EQ(status, ZX_OK) << "zx_object_get_property: ZX_PROP_PROCESS_DEBUG_ADDR"; // Can be 0 if requested before the loader has loaded anything. diff --git a/snapshot/fuchsia/memory_map_fuchsia.cc b/snapshot/fuchsia/memory_map_fuchsia.cc index b60531d0..15867929 100644 --- a/snapshot/fuchsia/memory_map_fuchsia.cc +++ b/snapshot/fuchsia/memory_map_fuchsia.cc @@ -14,8 +14,6 @@ #include "snapshot/fuchsia/memory_map_fuchsia.h" -#include <zircon/syscalls.h> - #include "base/fuchsia/fuchsia_logging.h" #include "util/numeric/checked_range.h" @@ -25,7 +23,7 @@ MemoryMapFuchsia::MemoryMapFuchsia() = default; MemoryMapFuchsia::~MemoryMapFuchsia() = default; -bool MemoryMapFuchsia::Initialize(zx_handle_t process) { +bool MemoryMapFuchsia::Initialize(const zx::process& process) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); // There's no way to know what an appropriate buffer size is before starting. @@ -40,12 +38,11 @@ bool MemoryMapFuchsia::Initialize(zx_handle_t process) { size_t actual; size_t available; zx_status_t status = - zx_object_get_info(process, - ZX_INFO_PROCESS_MAPS, - &map_entries_[0], - map_entries_.size() * sizeof(map_entries_[0]), - &actual, - &available); + process.get_info(ZX_INFO_PROCESS_MAPS, + &map_entries_[0], + map_entries_.size() * sizeof(map_entries_[0]), + &actual, + &available); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_object_get_info ZX_INFO_PROCESS_MAPS"; map_entries_.clear(); diff --git a/snapshot/fuchsia/memory_map_fuchsia.h b/snapshot/fuchsia/memory_map_fuchsia.h index 88df5695..c3511200 100644 --- a/snapshot/fuchsia/memory_map_fuchsia.h +++ b/snapshot/fuchsia/memory_map_fuchsia.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_SNAPSHOT_FUCHSIA_MEMORY_MAP_FUCHSIA_H_ #define CRASHPAD_SNAPSHOT_FUCHSIA_MEMORY_MAP_FUCHSIA_H_ +#include <lib/zx/process.h> #include <zircon/syscalls/object.h> #include <vector> @@ -33,7 +34,7 @@ class MemoryMapFuchsia { //! regions in the given process. //! //! \return `true` on success, or `false`, with an error logged. - bool Initialize(zx_handle_t process); + bool Initialize(const zx::process& process); //! \brief Searches through the previously retrieved memory map for the given //! address. If found, returns the deepest `zx_info_maps_t` mapping that diff --git a/snapshot/fuchsia/process_reader_fuchsia.cc b/snapshot/fuchsia/process_reader_fuchsia.cc index 0a6a84bb..40123018 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.cc +++ b/snapshot/fuchsia/process_reader_fuchsia.cc @@ -14,11 +14,11 @@ #include "snapshot/fuchsia/process_reader_fuchsia.h" +#include <lib/zx/thread.h> #include <link.h> #include <zircon/syscalls.h> #include "base/fuchsia/fuchsia_logging.h" -#include "base/fuchsia/scoped_zx_handle.h" #include "base/logging.h" #include "util/fuchsia/koid_utilities.h" @@ -83,15 +83,15 @@ ProcessReaderFuchsia::ProcessReaderFuchsia() = default; ProcessReaderFuchsia::~ProcessReaderFuchsia() = default; -bool ProcessReaderFuchsia::Initialize(zx_handle_t process) { +bool ProcessReaderFuchsia::Initialize(const zx::process& process) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); - process_ = process; + process_ = zx::unowned_process(process); process_memory_.reset(new ProcessMemoryFuchsia()); - process_memory_->Initialize(process_); + process_memory_->Initialize(*process_); - memory_map_.Initialize(process_); + memory_map_.Initialize(*process_); INITIALIZATION_STATE_SET_VALID(initialized_); return true; @@ -134,7 +134,7 @@ void ProcessReaderFuchsia::InitializeModules() { { char name[ZX_MAX_NAME_LEN]; zx_status_t status = - zx_object_get_property(process_, ZX_PROP_NAME, name, sizeof(name)); + process_->get_property(ZX_PROP_NAME, name, sizeof(name)); if (status != ZX_OK) { LOG(ERROR) << "zx_object_get_property ZX_PROP_NAME"; return; @@ -147,10 +147,8 @@ void ProcessReaderFuchsia::InitializeModules() { // walk the list to fill out modules_. uintptr_t debug_address; - zx_status_t status = zx_object_get_property(process_, - ZX_PROP_PROCESS_DEBUG_ADDR, - &debug_address, - sizeof(debug_address)); + zx_status_t status = process_->get_property( + ZX_PROP_PROCESS_DEBUG_ADDR, &debug_address, sizeof(debug_address)); if (status != ZX_OK || debug_address == 0) { LOG(ERROR) << "zx_object_get_property ZX_PROP_PROCESS_DEBUG_ADDR"; return; @@ -250,9 +248,9 @@ void ProcessReaderFuchsia::InitializeThreads() { initialized_threads_ = true; std::vector<zx_koid_t> thread_koids = - GetChildKoids(process_, ZX_INFO_PROCESS_THREADS); - std::vector<base::ScopedZxHandle> thread_handles = - GetHandlesForChildKoids(process_, thread_koids); + GetChildKoids(*process_, ZX_INFO_PROCESS_THREADS); + std::vector<zx::thread> thread_handles = + GetHandlesForThreadKoids(*process_, thread_koids); DCHECK_EQ(thread_koids.size(), thread_handles.size()); for (size_t i = 0; i < thread_handles.size(); ++i) { @@ -261,8 +259,8 @@ void ProcessReaderFuchsia::InitializeThreads() { if (thread_handles[i].is_valid()) { char name[ZX_MAX_NAME_LEN] = {0}; - zx_status_t status = zx_object_get_property( - thread_handles[i].get(), ZX_PROP_NAME, &name, sizeof(name)); + zx_status_t status = + thread_handles[i].get_property(ZX_PROP_NAME, &name, sizeof(name)); if (status != ZX_OK) { ZX_LOG(WARNING, status) << "zx_object_get_property ZX_PROP_NAME"; } else { @@ -270,12 +268,8 @@ void ProcessReaderFuchsia::InitializeThreads() { } zx_info_thread_t thread_info; - status = zx_object_get_info(thread_handles[i].get(), - ZX_INFO_THREAD, - &thread_info, - sizeof(thread_info), - nullptr, - nullptr); + status = thread_handles[i].get_info( + ZX_INFO_THREAD, &thread_info, sizeof(thread_info), nullptr, nullptr); if (status != ZX_OK) { ZX_LOG(WARNING, status) << "zx_object_get_info ZX_INFO_THREAD"; } else { @@ -283,10 +277,8 @@ void ProcessReaderFuchsia::InitializeThreads() { } zx_thread_state_general_regs_t regs; - status = zx_thread_read_state(thread_handles[i].get(), - ZX_THREAD_STATE_GENERAL_REGS, - ®s, - sizeof(regs)); + status = thread_handles[i].read_state( + ZX_THREAD_STATE_GENERAL_REGS, ®s, sizeof(regs)); if (status != ZX_OK) { ZX_LOG(WARNING, status) << "zx_thread_read_state"; } else { diff --git a/snapshot/fuchsia/process_reader_fuchsia.h b/snapshot/fuchsia/process_reader_fuchsia.h index 2d0878c3..6a6a6509 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.h +++ b/snapshot/fuchsia/process_reader_fuchsia.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_SNAPSHOT_FUCHSIA_PROCESS_READER_H_ #define CRASHPAD_SNAPSHOT_FUCHSIA_PROCESS_READER_H_ +#include <lib/zx/process.h> #include <zircon/syscalls/debug.h> #include <memory> @@ -94,7 +95,7 @@ class ProcessReaderFuchsia { //! \return `true` on success, indicating that this object will respond //! validly to further method calls. `false` on failure. On failure, no //! further method calls should be made. - bool Initialize(zx_handle_t process); + bool Initialize(const zx::process& process); //! \return The modules loaded in the process. The first element (at index //! `0`) corresponds to the main executable. @@ -121,7 +122,7 @@ class ProcessReaderFuchsia { std::vector<std::unique_ptr<ProcessMemoryRange>> process_memory_ranges_; std::unique_ptr<ProcessMemoryFuchsia> process_memory_; MemoryMapFuchsia memory_map_; - zx_handle_t process_; + zx::unowned_process process_; bool initialized_modules_ = false; bool initialized_threads_ = false; InitializationStateDcheck initialized_; diff --git a/snapshot/fuchsia/process_reader_fuchsia_test.cc b/snapshot/fuchsia/process_reader_fuchsia_test.cc index 546d8290..fe640082 100644 --- a/snapshot/fuchsia/process_reader_fuchsia_test.cc +++ b/snapshot/fuchsia/process_reader_fuchsia_test.cc @@ -31,7 +31,7 @@ namespace { TEST(ProcessReaderFuchsia, SelfBasic) { ProcessReaderFuchsia process_reader; - ASSERT_TRUE(process_reader.Initialize(zx_process_self())); + ASSERT_TRUE(process_reader.Initialize(*zx::process::self())); static constexpr char kTestMemory[] = "Some test memory"; char buffer[arraysize(kTestMemory)]; @@ -82,7 +82,7 @@ class BasicChildTest : public MultiprocessExec { private: void MultiprocessParent() override { ProcessReaderFuchsia process_reader; - ASSERT_TRUE(process_reader.Initialize(ChildProcess())); + ASSERT_TRUE(process_reader.Initialize(*ChildProcess())); zx_vaddr_t addr; ASSERT_TRUE(ReadFileExactly(ReadPipeHandle(), &addr, sizeof(addr))); @@ -149,10 +149,10 @@ class ThreadsChildTest : public MultiprocessExec { ASSERT_TRUE(ReadFileExactly(ReadPipeHandle(), &c, 1)); ASSERT_EQ(c, ' '); - ScopedTaskSuspend suspend(ChildProcess()); + ScopedTaskSuspend suspend(*ChildProcess()); ProcessReaderFuchsia process_reader; - ASSERT_TRUE(process_reader.Initialize(ChildProcess())); + ASSERT_TRUE(process_reader.Initialize(*ChildProcess())); const auto& threads = process_reader.Threads(); EXPECT_EQ(threads.size(), 6u); diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.cc b/snapshot/fuchsia/process_snapshot_fuchsia.cc index cc66db25..6750c3d5 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia.cc @@ -14,8 +14,6 @@ #include "snapshot/fuchsia/process_snapshot_fuchsia.h" -#include <zircon/process.h> - #include "base/logging.h" #include "util/fuchsia/koid_utilities.h" @@ -25,7 +23,7 @@ ProcessSnapshotFuchsia::ProcessSnapshotFuchsia() = default; ProcessSnapshotFuchsia::~ProcessSnapshotFuchsia() = default; -bool ProcessSnapshotFuchsia::Initialize(zx_handle_t process) { +bool ProcessSnapshotFuchsia::Initialize(const zx::process& process) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); if (gettimeofday(&snapshot_time_, nullptr) != 0) { @@ -95,7 +93,7 @@ void ProcessSnapshotFuchsia::GetCrashpadOptions( pid_t ProcessSnapshotFuchsia::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return GetKoidForHandle(zx_process_self()); + return GetKoidForHandle(*zx::process::self()); } pid_t ProcessSnapshotFuchsia::ParentProcessID() const { diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.h b/snapshot/fuchsia/process_snapshot_fuchsia.h index 2590ed58..237e17df 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.h +++ b/snapshot/fuchsia/process_snapshot_fuchsia.h @@ -15,9 +15,10 @@ #ifndef CRASHPAD_SNAPSHOT_FUCHSIA_PROCESS_SNAPSHOT_FUCHSIA_H_ #define CRASHPAD_SNAPSHOT_FUCHSIA_PROCESS_SNAPSHOT_FUCHSIA_H_ +#include <lib/zx/process.h> #include <sys/time.h> -#include <zircon/types.h> #include <zircon/syscalls/exception.h> +#include <zircon/types.h> #include <memory> #include <vector> @@ -50,7 +51,7 @@ class ProcessSnapshotFuchsia : public ProcessSnapshot { //! //! \return `true` if the snapshot could be created, `false` otherwise with //! an appropriate message logged. - bool Initialize(zx_handle_t process); + bool Initialize(const zx::process& process); //! \brief Initializes the object's exception. //! diff --git a/test/BUILD.gn b/test/BUILD.gn index d1e6297e..c9630653 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -101,7 +101,7 @@ static_library("test") { configs += [ "../build:crashpad_is_in_chromium", - "../build:crashpad_is_in_fuchsia" + "../build:crashpad_is_in_fuchsia", ] data = [ @@ -127,10 +127,13 @@ static_library("test") { libs = [ "shell32.lib" ] } - if (crashpad_is_fuchsia && crashpad_is_in_fuchsia) { - deps += [ - "//zircon/public/lib/fdio", + if (crashpad_is_fuchsia) { + public_deps = [ + "../third_party/fuchsia:zx", ] + if (crashpad_is_in_fuchsia) { + deps += [ "//zircon/public/lib/fdio" ] + } } } diff --git a/test/multiprocess_exec_fuchsia.cc b/test/multiprocess_exec_fuchsia.cc index 95436b47..9c68b7fd 100644 --- a/test/multiprocess_exec_fuchsia.cc +++ b/test/multiprocess_exec_fuchsia.cc @@ -16,13 +16,12 @@ #include <lib/fdio/io.h> #include <lib/fdio/spawn.h> -#include <zircon/process.h> +#include <lib/zx/process.h> +#include <lib/zx/time.h> #include <zircon/processargs.h> -#include <zircon/syscalls.h> #include "base/files/scoped_file.h" #include "base/fuchsia/fuchsia_logging.h" -#include "base/fuchsia/scoped_zx_handle.h" #include "gtest/gtest.h" namespace crashpad { @@ -49,7 +48,7 @@ struct MultiprocessInfo { MultiprocessInfo() {} base::ScopedFD stdin_write; base::ScopedFD stdout_read; - base::ScopedZxHandle child; + zx::process child; }; } // namespace internal @@ -68,19 +67,14 @@ void Multiprocess::Run() { // Wait until the child exits. zx_signals_t signals; ASSERT_EQ( - zx_object_wait_one( - info_->child.get(), ZX_TASK_TERMINATED, ZX_TIME_INFINITE, &signals), + info_->child.wait_one(ZX_TASK_TERMINATED, zx::time::infinite(), &signals), ZX_OK); ASSERT_EQ(signals, ZX_TASK_TERMINATED); // Get the child's exit code. zx_info_process_t proc_info; - zx_status_t status = zx_object_get_info(info_->child.get(), - ZX_INFO_PROCESS, - &proc_info, - sizeof(proc_info), - nullptr, - nullptr); + zx_status_t status = info_->child.get_info( + ZX_INFO_PROCESS, &proc_info, sizeof(proc_info), nullptr, nullptr); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_object_get_info"; ADD_FAILURE() << "Unable to get exit code of child"; @@ -188,7 +182,7 @@ void MultiprocessExec::MultiprocessChild() { uint32_t flags = FDIO_SPAWN_CLONE_ALL & ~FDIO_SPAWN_CLONE_STDIO; char error_message[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; - zx_handle_t child; + zx::process child; zx_status_t status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, command_.value().c_str(), @@ -196,14 +190,14 @@ void MultiprocessExec::MultiprocessChild() { nullptr, kActionCount, actions, - &child, + child.reset_and_get_address(), error_message); ZX_CHECK(status == ZX_OK, status) << "fdio_spawn_etc: " << error_message; - info()->child.reset(child); + info()->child = std::move(child); } ProcessType MultiprocessExec::ChildProcess() { - return info()->child.get(); + return zx::unowned_process(info()->child); } } // namespace test diff --git a/test/process_type.cc b/test/process_type.cc index 0e3c9e6d..9fd08dd9 100644 --- a/test/process_type.cc +++ b/test/process_type.cc @@ -15,7 +15,7 @@ #include "test/process_type.h" #if defined(OS_FUCHSIA) -#include <zircon/process.h> +#include <lib/zx/process.h> #elif defined(OS_POSIX) #include <unistd.h> #endif @@ -25,7 +25,7 @@ namespace test { ProcessType GetSelfProcess() { #if defined(OS_FUCHSIA) - return zx_process_self(); + return zx::process::self(); #elif defined(OS_POSIX) return getpid(); #elif defined(OS_WIN) diff --git a/test/process_type.h b/test/process_type.h index a25b1222..240c083d 100644 --- a/test/process_type.h +++ b/test/process_type.h @@ -18,7 +18,7 @@ #include "build/build_config.h" #if defined(OS_FUCHSIA) -#include <zircon/types.h> +#include <lib/zx/process.h> #elif defined(OS_POSIX) #include <sys/types.h> #elif defined(OS_WIN) @@ -29,7 +29,7 @@ namespace crashpad { namespace test { #if defined(OS_FUCHSIA) -using ProcessType = zx_handle_t; +using ProcessType = zx::unowned_process; #elif defined(OS_POSIX) || DOXYGEN //! \brief Alias for platform-specific type to represent a process. using ProcessType = pid_t; diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn new file mode 100644 index 00000000..6c2339b9 --- /dev/null +++ b/third_party/fuchsia/BUILD.gn @@ -0,0 +1,82 @@ +# Copyright 2018 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") + +if (crashpad_is_in_fuchsia) { + group("zx") { + public_deps = [ + "//zircon/public/lib/zx", + ] + } +} else if (crashpad_is_in_chromium) { + group("zx") { + public_deps = [ + "//third_party/fuchsia-sdk:zx", + ] + } +} else { + sdk_pkg_path = "sdk/linux-amd64/pkg" + + config("zx_config") { + visibility = [ ":zx" ] + include_dirs = [ "$sdk_pkg_path/zx/include" ] + } + + static_library("zx") { + sources = [ + "$sdk_pkg_path/zx/channel.cpp", + "$sdk_pkg_path/zx/event.cpp", + "$sdk_pkg_path/zx/eventpair.cpp", + "$sdk_pkg_path/zx/fifo.cpp", + "$sdk_pkg_path/zx/guest.cpp", + "$sdk_pkg_path/zx/include/lib/zx/bti.h", + "$sdk_pkg_path/zx/include/lib/zx/channel.h", + "$sdk_pkg_path/zx/include/lib/zx/event.h", + "$sdk_pkg_path/zx/include/lib/zx/eventpair.h", + "$sdk_pkg_path/zx/include/lib/zx/fifo.h", + "$sdk_pkg_path/zx/include/lib/zx/guest.h", + "$sdk_pkg_path/zx/include/lib/zx/handle.h", + "$sdk_pkg_path/zx/include/lib/zx/interrupt.h", + "$sdk_pkg_path/zx/include/lib/zx/job.h", + "$sdk_pkg_path/zx/include/lib/zx/log.h", + "$sdk_pkg_path/zx/include/lib/zx/object.h", + "$sdk_pkg_path/zx/include/lib/zx/object_traits.h", + "$sdk_pkg_path/zx/include/lib/zx/pmt.h", + "$sdk_pkg_path/zx/include/lib/zx/port.h", + "$sdk_pkg_path/zx/include/lib/zx/process.h", + "$sdk_pkg_path/zx/include/lib/zx/resource.h", + "$sdk_pkg_path/zx/include/lib/zx/socket.h", + "$sdk_pkg_path/zx/include/lib/zx/task.h", + "$sdk_pkg_path/zx/include/lib/zx/thread.h", + "$sdk_pkg_path/zx/include/lib/zx/time.h", + "$sdk_pkg_path/zx/include/lib/zx/timer.h", + "$sdk_pkg_path/zx/include/lib/zx/vmar.h", + "$sdk_pkg_path/zx/include/lib/zx/vmo.h", + "$sdk_pkg_path/zx/interrupt.cpp", + "$sdk_pkg_path/zx/job.cpp", + "$sdk_pkg_path/zx/log.cpp", + "$sdk_pkg_path/zx/port.cpp", + "$sdk_pkg_path/zx/process.cpp", + "$sdk_pkg_path/zx/resource.cpp", + "$sdk_pkg_path/zx/socket.cpp", + "$sdk_pkg_path/zx/thread.cpp", + "$sdk_pkg_path/zx/timer.cpp", + "$sdk_pkg_path/zx/vmar.cpp", + "$sdk_pkg_path/zx/vmo.cpp", + ] + + public_configs = [ ":zx_config" ] + } +} diff --git a/tools/generate_dump.cc b/tools/generate_dump.cc index 2cdaed27..9fb5a961 100644 --- a/tools/generate_dump.cc +++ b/tools/generate_dump.cc @@ -46,7 +46,8 @@ #include "util/win/scoped_process_suspend.h" #include "util/win/xp_compat.h" #elif defined(OS_FUCHSIA) -#include "base/fuchsia/scoped_zx_handle.h" +#include <lib/zx/process.h> + #include "snapshot/fuchsia/process_snapshot_fuchsia.h" #include "util/fuchsia/koid_utilities.h" #include "util/fuchsia/scoped_task_suspend.h" @@ -165,8 +166,8 @@ int GenerateDumpMain(int argc, char* argv[]) { return EXIT_FAILURE; } #elif defined(OS_FUCHSIA) - base::ScopedZxHandle task = GetProcessFromKoid(options.pid); - if (!task.is_valid()) { + zx::process process = GetProcessFromKoid(options.pid); + if (!process.is_valid()) { LOG(ERROR) << "could not open process " << options.pid; return EXIT_FAILURE; } @@ -190,7 +191,7 @@ int GenerateDumpMain(int argc, char* argv[]) { #elif defined(OS_FUCHSIA) std::unique_ptr<ScopedTaskSuspend> suspend; if (options.suspend) { - suspend.reset(new ScopedTaskSuspend(task.get())); + suspend.reset(new ScopedTaskSuspend(process)); } #endif // OS_MACOSX @@ -211,7 +212,7 @@ int GenerateDumpMain(int argc, char* argv[]) { } #elif defined(OS_FUCHSIA) ProcessSnapshotFuchsia process_snapshot; - if (!process_snapshot.Initialize(task.get())) { + if (!process_snapshot.Initialize(process)) { return EXIT_FAILURE; } #elif defined(OS_LINUX) || defined(OS_ANDROID) diff --git a/util/BUILD.gn b/util/BUILD.gn index 03220c9e..ec117573 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -454,6 +454,10 @@ static_library("util") { asmflags = [ "/safeseh" ] } } + + if (crashpad_is_fuchsia) { + public_deps += [ "../third_party/fuchsia:zx" ] + } } if (use_boringssl_for_http_transport_socket) { diff --git a/util/fuchsia/koid_utilities.cc b/util/fuchsia/koid_utilities.cc index 0d44f4af..65d3d94e 100644 --- a/util/fuchsia/koid_utilities.cc +++ b/util/fuchsia/koid_utilities.cc @@ -14,6 +14,8 @@ #include "util/fuchsia/koid_utilities.h" +#include <lib/zx/job.h> +#include <lib/zx/process.h> #include <zircon/device/sysinfo.h> #include <vector> @@ -26,62 +28,104 @@ namespace crashpad { namespace { -base::ScopedZxHandle GetRootJob() { +// Casts |handle| into a container of type T, returning a null handle if the +// actual handle type does not match that of T. +template <typename T> +T CastHandle(zx::handle handle) { + zx_info_handle_basic_t actual = {}; + zx_status_t status = handle.get_info( + ZX_INFO_HANDLE_BASIC, &actual, sizeof(actual), nullptr, nullptr); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_object_get_info"; + return T(); + } + if (actual.type != T::TYPE) { + LOG(ERROR) << "Wrong type: " << actual.type << ", expected " << T::TYPE; + return T(); + } + return T(std::move(handle)); +} + +zx::job GetRootJob() { ScopedFileHandle sysinfo( LoggingOpenFileForRead(base::FilePath("/dev/misc/sysinfo"))); if (!sysinfo.is_valid()) - return base::ScopedZxHandle(); + return zx::job(); - zx_handle_t root_job; - size_t n = ioctl_sysinfo_get_root_job(sysinfo.get(), &root_job); - if (n != sizeof(root_job)) { + zx::handle root_job; + size_t n = ioctl_sysinfo_get_root_job(sysinfo.get(), + root_job.reset_and_get_address()); + if (n != sizeof(zx_handle_t)) { LOG(ERROR) << "unexpected root job size"; - return base::ScopedZxHandle(); + return zx::job(); } - return base::ScopedZxHandle(root_job); + return CastHandle<zx::job>(std::move(root_job)); } -bool FindProcess(const base::ScopedZxHandle& job, - zx_koid_t koid, - base::ScopedZxHandle* out) { - for (auto& proc : GetChildHandles(job.get(), ZX_INFO_JOB_PROCESSES)) { - if (GetKoidForHandle(proc.get()) == koid) { - *out = std::move(proc); - return true; - } +// Returns null handle if |koid| is not found or an error occurs. If |was_found| +// is non-null then it will be set, to distinguish not-found from other errors. +template <typename T, typename U> +T GetChildHandleByKoid(const U& parent, zx_koid_t child_koid, bool* was_found) { + zx::handle handle; + zx_status_t status = + parent.get_child(child_koid, ZX_RIGHT_SAME_RIGHTS, &handle); + if (was_found) + *was_found = (status != ZX_ERR_NOT_FOUND); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_object_get_child"; + return T(); } - // TODO(scottmg): As this is recursing down the job tree all the handles are - // kept open, so this could be very expensive in terms of number of open - // handles. This function should be replaced by a syscall in the - // not-too-distant future, so hopefully OK for now. - for (const auto& child_job : - GetChildHandles(job.get(), ZX_INFO_JOB_CHILDREN)) { - if (FindProcess(child_job, koid, out)) - return true; + return CastHandle<T>(std::move(handle)); +} + +// Returns an invalid handle if the |koid| was found, but was of the wrong +// type, or we could not open a handle to it. +zx::process FindProcess(const zx::job& job, zx_koid_t koid, bool* was_found) { + DCHECK(!*was_found); + + // Look for |koid| as a direct descendent of |job|. + auto process = GetChildHandleByKoid<zx::process>(job, koid, was_found); + if (*was_found) { + // |koid| was found. |process| may still be null, e.g. if a handle could not + // be opened to it. + return process; } - return false; + // |koid| was not found under |job|, so search child jobs, if any. + // Since we only hold a handle to the job we are currently enumerating, child + // jobs may go away mid-enumeration. + for (auto child_koid : GetChildKoids(job, ZX_INFO_JOB_CHILDREN)) { + zx::job child_job = GetChildHandleByKoid<zx::job>(job, child_koid, nullptr); + if (!child_job.is_valid()) + continue; + zx::process process = FindProcess(child_job, koid, was_found); + if (*was_found) + return process; + } + + DCHECK(!*was_found); + return zx::process(); } } // namespace -std::vector<zx_koid_t> GetChildKoids(zx_handle_t parent, +std::vector<zx_koid_t> GetChildKoids(const zx::object_base& parent_object, zx_object_info_topic_t child_kind) { size_t actual = 0; size_t available = 0; std::vector<zx_koid_t> result(100); + zx::unowned_handle parent(parent_object.get()); // This is inherently racy. Better if the process is suspended, but there's // still no guarantee that a thread isn't externally created. As a result, // must be in a retry loop. for (;;) { - zx_status_t status = zx_object_get_info(parent, - child_kind, - result.data(), - result.size() * sizeof(zx_koid_t), - &actual, - &available); + zx_status_t status = parent->get_info(child_kind, + result.data(), + result.size() * sizeof(zx_koid_t), + &actual, + &available); // If the buffer is too small (even zero), the result is still ZX_OK, not // ZX_ERR_BUFFER_TOO_SMALL. if (status != ZX_OK) { @@ -102,42 +146,38 @@ std::vector<zx_koid_t> GetChildKoids(zx_handle_t parent, return result; } -std::vector<base::ScopedZxHandle> GetChildHandles(zx_handle_t parent, - zx_object_info_topic_t type) { - auto koids = GetChildKoids(parent, type); - return GetHandlesForChildKoids(parent, koids); +std::vector<zx::thread> GetThreadHandles(const zx::process& parent) { + auto koids = GetChildKoids(parent, ZX_INFO_PROCESS_THREADS); + return GetHandlesForThreadKoids(parent, koids); } -std::vector<base::ScopedZxHandle> GetHandlesForChildKoids( - zx_handle_t parent, +std::vector<zx::thread> GetHandlesForThreadKoids( + const zx::process& parent, const std::vector<zx_koid_t>& koids) { - std::vector<base::ScopedZxHandle> result; + std::vector<zx::thread> result; result.reserve(koids.size()); for (zx_koid_t koid : koids) { - result.emplace_back(GetChildHandleByKoid(parent, koid)); + result.emplace_back(GetThreadHandleByKoid(parent, koid)); } return result; } -base::ScopedZxHandle GetChildHandleByKoid(zx_handle_t parent, - zx_koid_t child_koid) { - zx_handle_t handle; - zx_status_t status = - zx_object_get_child(parent, child_koid, ZX_RIGHT_SAME_RIGHTS, &handle); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_object_get_child"; - return base::ScopedZxHandle(); - } - return base::ScopedZxHandle(handle); +zx::thread GetThreadHandleByKoid(const zx::process& parent, + zx_koid_t child_koid) { + return GetChildHandleByKoid<zx::thread>(parent, child_koid, nullptr); } -zx_koid_t GetKoidForHandle(zx_handle_t object) { +zx_koid_t GetKoidForHandle(const zx::object_base& object) { zx_info_handle_basic_t info; - zx_status_t status = zx_object_get_info( - object, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr); + zx_status_t status = zx_object_get_info(object.get(), + ZX_INFO_HANDLE_BASIC, + &info, + sizeof(info), + nullptr, + nullptr); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_object_get_info"; - return ZX_HANDLE_INVALID; + return ZX_KOID_INVALID; } return info.koid; } @@ -146,11 +186,11 @@ zx_koid_t GetKoidForHandle(zx_handle_t object) { // ioctls that are currently the only way to go from pid to handle. This should // hopefully eventually be replaced by more or less a single // zx_debug_something() syscall. -base::ScopedZxHandle GetProcessFromKoid(zx_koid_t koid) { - base::ScopedZxHandle result; - if (!FindProcess(GetRootJob(), koid, &result)) { +zx::process GetProcessFromKoid(zx_koid_t koid) { + bool was_found = false; + zx::process result = FindProcess(GetRootJob(), koid, &was_found); + if (!result.is_valid()) LOG(ERROR) << "process " << koid << " not found"; - } return result; } diff --git a/util/fuchsia/koid_utilities.h b/util/fuchsia/koid_utilities.h index 5bcea105..9848dced 100644 --- a/util/fuchsia/koid_utilities.h +++ b/util/fuchsia/koid_utilities.h @@ -15,13 +15,14 @@ #ifndef CRASHPAD_UTIL_FUCHSIA_KOID_UTILITIES_H_ #define CRASHPAD_UTIL_FUCHSIA_KOID_UTILITIES_H_ +#include <lib/zx/object.h> +#include <lib/zx/process.h> +#include <lib/zx/thread.h> #include <zircon/syscalls/object.h> #include <zircon/types.h> #include <vector> -#include "base/fuchsia/scoped_zx_handle.h" - namespace crashpad { //! \brief Get a list of child koids for a parent handle. @@ -38,57 +39,50 @@ namespace crashpad { //! \return A vector of the koids representing the child objects. //! //! \sa GetChildHandles -std::vector<zx_koid_t> GetChildKoids(zx_handle_t parent, +std::vector<zx_koid_t> GetChildKoids(const zx::object_base& parent, zx_object_info_topic_t child_kind); //! \brief Get handles representing a list of child objects of a given parent. //! //! \param[in] parent The handle to the parent object. -//! \param[in] child_kind The type of children to retrieve from \a parent. Valid -//! values depend on the type of \a parent, but include -//! `ZX_INFO_JOB_CHILDREN` (child jobs of a job), `ZX_INFO_JOB_PROCESSES` -//! (child processes of a job), and `ZX_INFO_PROCESS_THREADS` (child threads -//! of a process). //! \return The resulting list of handles corresponding to the child objects. //! //! \sa GetChildKoids -std::vector<base::ScopedZxHandle> GetChildHandles( - zx_handle_t parent, - zx_object_info_topic_t child_kind); +std::vector<zx::thread> GetThreadHandles(const zx::process& parent); -//! \brief Convert a list of koids that are all children of a particular object -//! into handles. +//! \brief Convert a list of koids that are all children of a particular process +//! into thread handles. //! //! \param[in] parent The parent object to which the koids belong. //! \param[in] koids The list of koids. //! \return The resulting list of handles corresponding to the koids. If an //! element of \a koids is invalid or can't be retrieved, there will be a //! corresponding `ZX_HANDLE_INVALID` entry in the return. -std::vector<base::ScopedZxHandle> GetHandlesForChildKoids( - zx_handle_t parent, +std::vector<zx::thread> GetHandlesForThreadKoids( + const zx::process& parent, const std::vector<zx_koid_t>& koids); -//! \brief Retrieve the child of a parent handle, based on koid. +//! \brief Retrieve the handle of a process' thread, based on koid. //! //! \param[in] parent The parent object to which the child belongs. //! \param[in] child_koid The koid of the child to retrieve. //! \return A handle representing \a child_koid, or `ZX_HANDLE_INVALID` if the //! handle could not be retrieved, in which case an error will be logged. -base::ScopedZxHandle GetChildHandleByKoid(zx_handle_t parent, - zx_koid_t child_koid); +zx::thread GetThreadHandleByKoid(const zx::process& parent, + zx_koid_t child_koid); //! \brief Gets a process handle given the process' koid. //! //! \param[in] koid The process id. //! \return A zx_handle_t (owned by a base::ScopedZxHandle) for the process. If //! the handle is invalid, an error will have been logged. -base::ScopedZxHandle GetProcessFromKoid(zx_koid_t koid); +zx::process GetProcessFromKoid(zx_koid_t koid); //! \brief Retrieves the koid for a given object handle. //! //! \param[in] object The handle for which the koid is to be retrieved. //! \return The koid of \a handle, or `ZX_HANDLE_INVALID` with an error logged. -zx_koid_t GetKoidForHandle(zx_handle_t object); +zx_koid_t GetKoidForHandle(const zx::object_base& object); } // namespace crashpad diff --git a/util/fuchsia/scoped_task_suspend.cc b/util/fuchsia/scoped_task_suspend.cc index ca0fd564..0daaf635 100644 --- a/util/fuchsia/scoped_task_suspend.cc +++ b/util/fuchsia/scoped_task_suspend.cc @@ -14,14 +14,11 @@ #include "util/fuchsia/scoped_task_suspend.h" -#include <zircon/process.h> -#include <zircon/syscalls.h> -#include <zircon/syscalls/debug.h> +#include <lib/zx/time.h> #include <vector> #include "base/fuchsia/fuchsia_logging.h" -#include "base/fuchsia/scoped_zx_handle.h" #include "base/logging.h" #include "util/fuchsia/koid_utilities.h" @@ -29,53 +26,37 @@ namespace crashpad { namespace { -zx_obj_type_t GetHandleType(zx_handle_t handle) { - zx_info_handle_basic_t basic; - zx_status_t status = zx_object_get_info( - handle, ZX_INFO_HANDLE_BASIC, &basic, sizeof(basic), nullptr, nullptr); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_object_get_info"; - return ZX_OBJ_TYPE_NONE; - } - return basic.type; -} - // Returns the suspend token of the suspended thread. This function attempts // to wait a short time for the thread to actually suspend before returning // but this is not guaranteed. -base::ScopedZxHandle SuspendThread(zx_handle_t thread) { - zx_handle_t token = ZX_HANDLE_INVALID; - zx_status_t status = zx_task_suspend_token(thread, &token); +zx::suspend_token SuspendThread(const zx::thread& thread) { + zx::suspend_token token; + zx_status_t status = thread.suspend(&token); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_task_suspend"; - base::ScopedZxHandle(); + return zx::suspend_token(); } zx_signals_t observed = 0u; - if (zx_object_wait_one(thread, ZX_THREAD_SUSPENDED, - zx_deadline_after(ZX_MSEC(50)), &observed) != ZX_OK) { + if (thread.wait_one(ZX_THREAD_SUSPENDED, + zx::deadline_after(zx::msec(50)), + &observed) != ZX_OK) { LOG(ERROR) << "thread failed to suspend"; } - return base::ScopedZxHandle(token); + return token; } } // namespace -ScopedTaskSuspend::ScopedTaskSuspend(zx_handle_t task) { - DCHECK_NE(task, zx_process_self()); - DCHECK_NE(task, zx_thread_self()); - - zx_obj_type_t type = GetHandleType(task); - if (type == ZX_OBJ_TYPE_THREAD) { - suspend_tokens_.push_back(SuspendThread(task)); - } else if (type == ZX_OBJ_TYPE_PROCESS) { - for (const auto& thread : GetChildHandles(task, ZX_INFO_PROCESS_THREADS)) - suspend_tokens_.push_back(SuspendThread(thread.get())); - } else { - LOG(ERROR) << "unexpected handle type"; - } +ScopedTaskSuspend::ScopedTaskSuspend(const zx::process& process) { + DCHECK_NE(process.get(), zx::process::self()->get()); + for (const auto& thread : GetThreadHandles(process)) + suspend_tokens_.push_back(SuspendThread(thread)); } -ScopedTaskSuspend::~ScopedTaskSuspend() = default; +ScopedTaskSuspend::ScopedTaskSuspend(const zx::thread& thread) { + DCHECK_NE(thread.get(), zx::thread::self()->get()); + suspend_tokens_.push_back(SuspendThread(thread)); +} } // namespace crashpad diff --git a/util/fuchsia/scoped_task_suspend.h b/util/fuchsia/scoped_task_suspend.h index f817364d..251904a8 100644 --- a/util/fuchsia/scoped_task_suspend.h +++ b/util/fuchsia/scoped_task_suspend.h @@ -15,11 +15,12 @@ #ifndef CRASHPAD_UTIL_FUCHSIA_SCOPED_TASK_SUSPEND_H_ #define CRASHPAD_UTIL_FUCHSIA_SCOPED_TASK_SUSPEND_H_ -#include <zircon/types.h> +#include <lib/zx/process.h> +#include <lib/zx/suspend_token.h> +#include <lib/zx/thread.h> #include <vector> -#include "base/fuchsia/scoped_zx_handle.h" #include "base/macros.h" namespace crashpad { @@ -40,12 +41,13 @@ namespace crashpad { //! `zx_process_self()`. class ScopedTaskSuspend { public: - explicit ScopedTaskSuspend(zx_handle_t task); - ~ScopedTaskSuspend(); + explicit ScopedTaskSuspend(const zx::process& process); + explicit ScopedTaskSuspend(const zx::thread& thread); + ~ScopedTaskSuspend() = default; private: - // Could be one (for a thread) or many (for every process in a thread). - std::vector<base::ScopedZxHandle> suspend_tokens_; + // Could be one (for a thread) or many (for every thread in a process). + std::vector<zx::suspend_token> suspend_tokens_; DISALLOW_COPY_AND_ASSIGN(ScopedTaskSuspend); }; diff --git a/util/process/process_memory_fuchsia.cc b/util/process/process_memory_fuchsia.cc index 212e1c6f..b9c4a0c3 100644 --- a/util/process/process_memory_fuchsia.cc +++ b/util/process/process_memory_fuchsia.cc @@ -14,8 +14,6 @@ #include "util/process/process_memory_fuchsia.h" -#include <zircon/syscalls.h> - #include <limits> #include "base/logging.h" @@ -28,9 +26,13 @@ ProcessMemoryFuchsia::ProcessMemoryFuchsia() ProcessMemoryFuchsia::~ProcessMemoryFuchsia() {} -bool ProcessMemoryFuchsia::Initialize(zx_handle_t process) { +bool ProcessMemoryFuchsia::Initialize(const zx::unowned_process& process) { + return Initialize(*process); +} + +bool ProcessMemoryFuchsia::Initialize(const zx::process& process) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); - process_ = process; + process_ = zx::unowned_process(process); INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -42,8 +44,7 @@ ssize_t ProcessMemoryFuchsia::ReadUpTo(VMAddress address, DCHECK_LE(size, size_t{std::numeric_limits<ssize_t>::max()}); size_t actual; - zx_status_t status = - zx_process_read_memory(process_, address, buffer, size, &actual); + zx_status_t status = process_->read_memory(address, buffer, size, &actual); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_process_read_memory"; diff --git a/util/process/process_memory_fuchsia.h b/util/process/process_memory_fuchsia.h index e6cdd3e8..6c9cebaa 100644 --- a/util/process/process_memory_fuchsia.h +++ b/util/process/process_memory_fuchsia.h @@ -15,7 +15,7 @@ #ifndef CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_FUCHSIA_H_ #define CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_FUCHSIA_H_ -#include <zircon/types.h> +#include <lib/zx/process.h> #include <string> @@ -40,12 +40,15 @@ class ProcessMemoryFuchsia final : public ProcessMemory { //! \param[in] process The handle to the target process. //! //! \return `true` on success, `false` on failure with a message logged. - bool Initialize(zx_handle_t process); + bool Initialize(const zx::process& process); + // TODO(wez): Remove this overload when zx::unowned_process allows implicit + // copy. + bool Initialize(const zx::unowned_process& process); private: ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) const override; - zx_handle_t process_; + zx::unowned_process process_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ProcessMemoryFuchsia); diff --git a/util/process/process_memory_range_test.cc b/util/process/process_memory_range_test.cc index 1c785068..3784e95d 100644 --- a/util/process/process_memory_range_test.cc +++ b/util/process/process_memory_range_test.cc @@ -24,7 +24,7 @@ #include "util/misc/from_pointer_cast.h" #if defined(OS_FUCHSIA) -#include <zircon/process.h> +#include <lib/zx/process.h> #include "util/process/process_memory_fuchsia.h" #else @@ -43,7 +43,7 @@ struct TestObject { TEST(ProcessMemoryRange, Basic) { #if defined(OS_FUCHSIA) ProcessMemoryFuchsia memory; - ASSERT_TRUE(memory.Initialize(zx_process_self())); + ASSERT_TRUE(memory.Initialize(*zx::process::self())); constexpr bool is_64_bit = true; #else pid_t pid = getpid(); From 9cd2bae5ab23e17918f0b68dd1bd86ab07af712a Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 1 Aug 2018 08:42:27 -0700 Subject: [PATCH 002/401] Use Microsoft's ARM64 context layout Change-Id: Ic92447e99474f9b24197375acfc324cca4899222 Reviewed-on: https://chromium-review.googlesource.com/1157286 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- minidump/minidump_context.h | 54 ++++++++++++++++----- minidump/minidump_context_writer.cc | 27 +++++++---- minidump/test/minidump_context_test_util.cc | 4 +- 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/minidump/minidump_context.h b/minidump/minidump_context.h index 6f51b5a4..3a3e603c 100644 --- a/minidump/minidump_context.h +++ b/minidump/minidump_context.h @@ -389,11 +389,16 @@ struct MinidumpContextARM { //! \brief 64-bit ARM-specifc flags for MinidumpContextARM64::context_flags. enum MinidumpContextARM64Flags : uint32_t { //! \brief Identifies the context structure as 64-bit ARM. - kMinidumpContextARM64 = 0x80000000, + kMinidumpContextARM64 = 0x00400000, + + //! \brief Indicates the validity of control registers. + //! + //! Registers `fp`, `lr`, `sp`, `pc`, and `cpsr`. + kMinidumpContextARM64Control = kMinidumpContextARM64 | 0x00000001, //! \brief Indicates the validty of integer registers. //! - //! Registers `x0`-`x31`, `pc`, and `cpsr`. + //! Registers `x0`-`x28`. kMinidumpContextARM64Integer = kMinidumpContextARM64 | 0x00000002, //! \brief Indicates the validity of fpsimd registers. @@ -401,17 +406,37 @@ enum MinidumpContextARM64Flags : uint32_t { //! Registers `v0`-`v31`, `fpsr`, and `fpcr` are valid. kMinidumpContextARM64Fpsimd = kMinidumpContextARM64 | 0x00000004, + //! \brief Indicates the validity of debug registers. + //! + //! `bcr`, `bvr`, `wcr`, and `wvr` are valid. + kMinidumpContextARM64Debug = kMinidumpContextARM64 | 0x00000008, + + //! \brief Indicates the validity of control, integer and floating point + //! registers. + kMinidumpContextARM64Full = kMinidumpContextARM64Control | + kMinidumpContextARM64Integer | + kMinidumpContextARM64Fpsimd, + //! \brief Indicates the validity of all registers. kMinidumpContextARM64All = - kMinidumpContextARM64Integer | kMinidumpContextARM64Fpsimd, + kMinidumpContextARM64Full | kMinidumpContextARM64Debug, }; //! \brief A 64-bit ARM CPU context (register state) carried in a minidump file. struct MinidumpContextARM64 { - uint64_t context_flags; + uint32_t context_flags; - //! \brief General-purpose registers `x0`-`x30`. - uint64_t regs[31]; + //! \brief Current program status register. + uint32_t cpsr; + + //! \brief General-purpose registers `x0`-`x28`. + uint64_t regs[29]; + + //! \brief Frame pointer or `x29`. + uint64_t fp; + + //! \brief Link register or `x30`. + uint64_t lr; //! \brief Stack pointer or `x31`. uint64_t sp; @@ -419,17 +444,20 @@ struct MinidumpContextARM64 { //! \brief Program counter. uint64_t pc; - //! \brief Current program status register. - uint32_t cpsr; - - //! \brief Floating-point status register. - uint32_t fpsr; + //! \brief NEON registers `v0`-`v31`. + uint128_struct fpsimd[32]; //! \brief Floating-point control register. uint32_t fpcr; - //! \brief NEON registers `v0`-`v31`. - uint128_struct fpsimd[32]; + //! \brief Floating-point status register. + uint32_t fpsr; + + //! \brief Debug registers. + uint32_t bcr[8]; + uint64_t bvr[8]; + uint32_t wcr[2]; + uint64_t wvr[2]; }; //! \brief 32bit MIPS-specifc flags for MinidumpContextMIPS::context_flags. diff --git a/minidump/minidump_context_writer.cc b/minidump/minidump_context_writer.cc index 20adbf3f..b67e2bfe 100644 --- a/minidump/minidump_context_writer.cc +++ b/minidump/minidump_context_writer.cc @@ -321,13 +321,7 @@ void MinidumpContextARM64Writer::InitializeFromSnapshot( DCHECK_EQ(state(), kStateMutable); DCHECK_EQ(context_.context_flags, kMinidumpContextARM64); - context_.context_flags = kMinidumpContextARM64All; - - static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs), - "GPRs size mismatch"); - memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs)); - context_.sp = context_snapshot->sp; - context_.pc = context_snapshot->pc; + context_.context_flags = kMinidumpContextARM64Full; if (context_snapshot->pstate > std::numeric_limits<decltype(context_.cpsr)>::max()) { @@ -336,11 +330,26 @@ void MinidumpContextARM64Writer::InitializeFromSnapshot( context_.cpsr = static_cast<decltype(context_.cpsr)>(context_snapshot->pstate); - context_.fpsr = context_snapshot->fpsr; - context_.fpcr = context_snapshot->fpcr; + static_assert( + sizeof(context_.regs) == sizeof(context_snapshot->regs) - + 2 * sizeof(context_snapshot->regs[0]), + "GPRs size mismatch"); + memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs)); + context_.fp = context_snapshot->regs[29]; + context_.lr = context_snapshot->regs[30]; + context_.sp = context_snapshot->sp; + context_.pc = context_snapshot->pc; + static_assert(sizeof(context_.fpsimd) == sizeof(context_snapshot->fpsimd), "FPSIMD size mismatch"); memcpy(context_.fpsimd, context_snapshot->fpsimd, sizeof(context_.fpsimd)); + context_.fpcr = context_snapshot->fpcr; + context_.fpsr = context_snapshot->fpsr; + + memset(context_.bcr, 0, sizeof(context_.bcr)); + memset(context_.bvr, 0, sizeof(context_.bvr)); + memset(context_.wcr, 0, sizeof(context_.wcr)); + memset(context_.wvr, 0, sizeof(context_.wvr)); } bool MinidumpContextARM64Writer::WriteObject(FileWriterInterface* file_writer) { diff --git a/minidump/test/minidump_context_test_util.cc b/minidump/test/minidump_context_test_util.cc index 28f94106..318b3fc9 100644 --- a/minidump/test/minidump_context_test_util.cc +++ b/minidump/test/minidump_context_test_util.cc @@ -176,13 +176,15 @@ void InitializeMinidumpContextARM64(MinidumpContextARM64* context, return; } - context->context_flags = kMinidumpContextARM64All; + context->context_flags = kMinidumpContextARM64Full; uint32_t value = seed; for (size_t index = 0; index < arraysize(context->regs); ++index) { context->regs[index] = value++; } + context->fp = value++; + context->lr = value++; context->sp = value++; context->pc = value++; context->cpsr = value++; From 2906581f1051175d39df473545827bc15dbf53b6 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 8 Aug 2018 10:46:21 -0400 Subject: [PATCH 003/401] win: Fix GYP build of http_transport_test_server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The C++ http_transport_test_server was added in 439ba730c5ae and the missing GYP build description was corrected in 0e144fb9aeff, but this wasn’t complete for Windows. ws2_32.lib was missing. Bug: crashpad:227 Change-Id: I2a0810468f857a02ad1a997c569eee6d9c05c7da Reviewed-on: https://chromium-review.googlesource.com/1167210 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/util_test.gyp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/util/util_test.gyp b/util/util_test.gyp index ff3559e3..485ed663 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -193,6 +193,15 @@ 'cflags!': [ '-Wexit-time-destructors', ], + 'conditions': [ + ['OS=="win"', { + 'link_settings': { + 'libraries': [ + '-lws2_32.lib', + ], + }, + }], + ], }, ], }], From f540abb506acc7be53a4702f87d291930967d001 Mon Sep 17 00:00:00 2001 From: Jeremy Apthorp <jeremya@chromium.org> Date: Thu, 9 Aug 2018 16:41:44 -0700 Subject: [PATCH 004/401] Treat response codes in [200..203] as successful Some crash recorders respond with non-200 2xx responses on success, e.g. HockeyApp which responds with 202 Accepted. Change-Id: I40de12155b44f7638a1c726090657938e3b1b557 Reviewed-on: https://chromium-review.googlesource.com/1167793 Commit-Queue: Jeremy Apthorp <jeremya@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/net/http_transport.h | 2 +- util/net/http_transport_mac.mm | 2 +- util/net/http_transport_socket.cc | 16 ++++++++++++---- util/net/http_transport_test.cc | 2 +- util/net/http_transport_win.cc | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/util/net/http_transport.h b/util/net/http_transport.h index f91a5561..acd4e442 100644 --- a/util/net/http_transport.h +++ b/util/net/http_transport.h @@ -90,7 +90,7 @@ class HTTPTransport { //! if the response body is not required. //! //! \return Whether or not the request was successful, defined as returning - //! a HTTP status 200 (OK) code. + //! a HTTP status code in the range 200-203 (inclusive). virtual bool ExecuteSynchronously(std::string* response_body) = 0; protected: diff --git a/util/net/http_transport_mac.mm b/util/net/http_transport_mac.mm index 8d5f78cc..a433bb35 100644 --- a/util/net/http_transport_mac.mm +++ b/util/net/http_transport_mac.mm @@ -293,7 +293,7 @@ bool HTTPTransportMac::ExecuteSynchronously(std::string* response_body) { return false; } NSInteger http_status = [http_response statusCode]; - if (http_status != 200) { + if (http_status < 200 || http_status > 203) { LOG(ERROR) << base::StringPrintf("HTTP status %ld", implicit_cast<long>(http_status)); return false; diff --git a/util/net/http_transport_socket.cc b/util/net/http_transport_socket.cc index f0e2dc14..34d8deeb 100644 --- a/util/net/http_transport_socket.cc +++ b/util/net/http_transport_socket.cc @@ -457,10 +457,18 @@ bool ReadResponseLine(Stream* stream) { LOG(ERROR) << "ReadLine"; return false; } - static constexpr const char kHttp10[] = "HTTP/1.0 200 "; - static constexpr const char kHttp11[] = "HTTP/1.1 200 "; - return StartsWith(response_line, kHttp10, strlen(kHttp10)) || - StartsWith(response_line, kHttp11, strlen(kHttp11)); + static constexpr const char kHttp10[] = "HTTP/1.0 "; + static constexpr const char kHttp11[] = "HTTP/1.1 "; + if (!(StartsWith(response_line, kHttp10, strlen(kHttp10)) || + StartsWith(response_line, kHttp11, strlen(kHttp11))) || + response_line.size() < strlen(kHttp10) + 3 || + response_line.at(strlen(kHttp10) + 3) != ' ') { + return false; + } + unsigned int http_status = 0; + return base::StringToUint(response_line.substr(strlen(kHttp10), 3), + &http_status) && + http_status >= 200 && http_status <= 203; } bool ReadResponseHeaders(Stream* stream, HTTPHeaders* headers) { diff --git a/util/net/http_transport_test.cc b/util/net/http_transport_test.cc index 7b5f41df..d73dc992 100644 --- a/util/net/http_transport_test.cc +++ b/util/net/http_transport_test.cc @@ -137,7 +137,7 @@ class HTTPTransportTestFixture : public MultiprocessExec { std::string response_body; bool success = transport->ExecuteSynchronously(&response_body); - if (response_code_ == 200) { + if (response_code_ >= 200 && response_code_ <= 203) { EXPECT_TRUE(success); std::string expect_response_body = random_string + "\r\n"; EXPECT_EQ(response_body, expect_response_body); diff --git a/util/net/http_transport_win.cc b/util/net/http_transport_win.cc index 18d343cc..2919bc11 100644 --- a/util/net/http_transport_win.cc +++ b/util/net/http_transport_win.cc @@ -375,7 +375,7 @@ bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) { return false; } - if (status_code != 200) { + if (status_code < 200 || status_code > 203) { LOG(ERROR) << base::StringPrintf("HTTP status %lu", status_code); return false; } From e6f26587e4356007bb506767f3fc49870d87d8c3 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 10 Aug 2018 23:34:06 -0400 Subject: [PATCH 005/401] fuchsia, net: Disable TLS, not currently working for in-Fuchsia tests Bug: DX-382 Change-Id: I06a0a71c32d8d28d30b1add8a2bd57f1d6462463 Reviewed-on: https://chromium-review.googlesource.com/1171984 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/BUILD.gn | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index ec117573..88ef1021 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -15,7 +15,9 @@ import("../build/crashpad_buildconfig.gni") declare_args() { - use_boringssl_for_http_transport_socket = crashpad_is_fuchsia + # This should at least be on for Fuchsia, but DX-382 happened. + # TODO(mark): Figure out what went wrong and re-enable. + use_boringssl_for_http_transport_socket = false } if (crashpad_is_mac) { From 606368a39341f014b24b75a5cc2400f821aa3c71 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 13 Aug 2018 15:10:45 -0700 Subject: [PATCH 006/401] linux: Use correct handler argument for client FDs This worked before because getopt also accepts prefixes of known options. Change-Id: I0a479ad17954c541e84dc77230abcff19e8fae72 Reviewed-on: https://chromium-review.googlesource.com/1173439 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client_linux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 54fe268a..6a7c638c 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -199,7 +199,7 @@ bool CrashpadClient::StartHandlerForClient( std::vector<std::string> argv = BuildHandlerArgvStrings( handler, database, metrics_dir, url, annotations, arguments); - argv.push_back(FormatArgumentInt("initial-client", socket)); + argv.push_back(FormatArgumentInt("initial-client-fd", socket)); return DoubleForkAndExec(argv, socket, true, nullptr); } From f8b0538406ea35cd19beb33f1f9c48807c670014 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 13 Aug 2018 19:24:49 -0400 Subject: [PATCH 007/401] =?UTF-8?q?fuchsia:=20Don=E2=80=99t=20require=20te?= =?UTF-8?q?st=20certificate=20setup=20for=20disabled=20TLS=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to e6f26587e435. Bug: DX-382 Change-Id: I3116ea5dd2eca33961465d62c9200aa8dd1baf5d Reviewed-on: https://chromium-review.googlesource.com/1173339 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- BUILD.gn | 31 +++++++++++++++++++------------ util/BUILD.gn | 15 +++++---------- util/net/tls.gni | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 util/net/tls.gni diff --git a/BUILD.gn b/BUILD.gn index 065a5e1f..6da79cb6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -14,6 +14,7 @@ import("build/crashpad_buildconfig.gni") import("build/test.gni") +import("util/net/tls.gni") config("crashpad_config") { include_dirs = [ "." ] @@ -45,7 +46,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "snapshot:crashpad_snapshot_test_module_large", "snapshot:crashpad_snapshot_test_module_small", "test:crashpad_test_test_multiprocess_exec_test_child", - "util:generate_test_server_key", "util:http_transport_test_server", ] @@ -61,17 +61,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { name = "http_transport_test_server" dest = "crashpad_test_data/http_transport_test_server" }, - - # These aren't actually tests, but that seems to be the only way to - # convince package() to get them from the output directory. - { - name = "crashpad_util_test_cert.pem" - dest = "crashpad_test_data/crashpad_util_test_cert.pem" - }, - { - name = "crashpad_util_test_key.pem" - dest = "crashpad_test_data/crashpad_util_test_key.pem" - }, ] loadable_modules = [ @@ -103,6 +92,24 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { dest = "crashpad_test_data/test/test_paths_test_data_root.txt" }, ] + + if (crashpad_use_boringssl_for_http_transport_socket) { + deps += [ + "util:generate_test_server_key", + ] + tests += [ + # These aren't actually tests, but that seems to be the only way to + # convince package() to get them from the output directory. + { + name = "crashpad_util_test_cert.pem" + dest = "crashpad_test_data/crashpad_util_test_cert.pem" + }, + { + name = "crashpad_util_test_key.pem" + dest = "crashpad_test_data/crashpad_util_test_key.pem" + }, + ] + } } package("crashpad_handler") { diff --git a/util/BUILD.gn b/util/BUILD.gn index 88ef1021..bb15300b 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -13,12 +13,7 @@ # limitations under the License. import("../build/crashpad_buildconfig.gni") - -declare_args() { - # This should at least be on for Fuchsia, but DX-382 happened. - # TODO(mark): Figure out what went wrong and re-enable. - use_boringssl_for_http_transport_socket = false -} +import("net/tls.gni") if (crashpad_is_mac) { if (crashpad_is_in_chromium) { @@ -256,7 +251,7 @@ static_library("util") { if (crashpad_is_linux || crashpad_is_fuchsia) { sources += [ "net/http_transport_socket.cc" ] - if (use_boringssl_for_http_transport_socket) { + if (crashpad_use_boringssl_for_http_transport_socket) { defines = [ "CRASHPAD_USE_BORINGSSL" ] if (crashpad_is_in_fuchsia) { @@ -462,7 +457,7 @@ static_library("util") { } } -if (use_boringssl_for_http_transport_socket) { +if (crashpad_use_boringssl_for_http_transport_socket) { action("generate_test_server_key") { script = "net/generate_test_server_key.py" outputs = [ @@ -496,7 +491,7 @@ if (!crashpad_is_android) { libs = [ "ws2_32.lib" ] } - if (use_boringssl_for_http_transport_socket) { + if (crashpad_use_boringssl_for_http_transport_socket) { data_deps = [ ":generate_test_server_key", ] @@ -664,7 +659,7 @@ source_set("util_test") { ":http_transport_test_server", ] - if (use_boringssl_for_http_transport_socket) { + if (crashpad_use_boringssl_for_http_transport_socket) { defines = [ "CRASHPAD_USE_BORINGSSL" ] } } diff --git a/util/net/tls.gni b/util/net/tls.gni new file mode 100644 index 00000000..68c7eb7d --- /dev/null +++ b/util/net/tls.gni @@ -0,0 +1,19 @@ +# Copyright 2018 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. + +declare_args() { + # This should at least be on for Fuchsia, but DX-382 happened. + # TODO(mark): Figure out what went wrong and re-enable. + crashpad_use_boringssl_for_http_transport_socket = false +} From 3ab5d5eff2b9c2aa86db12316dee5b089f8b6b92 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 15 Aug 2018 14:08:57 -0400 Subject: [PATCH 008/401] Update mini_chromium to 8d641e30a8b12088649606b912c2bc4947419ccc 5544d67ab99a [fuchsia] Update to zx_cprng_draw dd77be1abce5 [Fuchsia] Remove unused 'launchpad' include path. 8d641e30a8b1 Remove unused base::ScopedZxHandle. This is needed because the transitional zx_cprng_draw_new() has been removed from Fuchsia in Zircon 9b5f75446d37, and there is now only zx_cprng_draw(). Change-Id: I182e74bc2fb3df6f8eaabe6400a544d611b29976 Reviewed-on: https://chromium-review.googlesource.com/1176124 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 34f1ef68..8a1ba5ab 100644 --- a/DEPS +++ b/DEPS @@ -30,7 +30,7 @@ deps = { '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '793e94e2c652831af2d25bb5288b04e59048c62d', + '8d641e30a8b12088649606b912c2bc4947419ccc', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 5c6e19f0001e29915be2e7cd08731e00f4007ca5 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 15 Aug 2018 13:27:22 -0400 Subject: [PATCH 009/401] Use std::shuffle instead of std::random_shuffle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mcgrathr points out in https://chromium-review.googlesource.com/1172090 that std::random_shuffle is deprecated in C++14 and removed in C++17. Rather than having mini_chromium mimic Chromium’s base by providing RandomShuffle (Chromium 5de2157f1e7f), just use the standard library’s std::shuffle with mt19937(random_generator). Change-Id: I8c2b3101bf324350351dba9edda1ba230b1c6710 Reviewed-on: https://chromium-review.googlesource.com/1176122 Reviewed-by: Robert Sesek <rsesek@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- client/prune_crash_reports_test.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/client/prune_crash_reports_test.cc b/client/prune_crash_reports_test.cc index 01990d27..9f5852e6 100644 --- a/client/prune_crash_reports_test.cc +++ b/client/prune_crash_reports_test.cc @@ -18,11 +18,11 @@ #include <stdlib.h> #include <algorithm> +#include <random> #include <string> #include <vector> #include "base/numerics/safe_conversions.h" -#include "base/rand_util.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "test/scoped_temp_dir.h" @@ -218,11 +218,8 @@ TEST(PruneCrashReports, PruneOrder) { temp.creation_time = NDaysAgo(i * 10); reports.push_back(temp); } - // The randomness from std::rand() is not, so use a better rand() instead. - const auto random_generator = [](ptrdiff_t rand_max) { - return base::RandInt(0, base::checked_cast<int>(rand_max) - 1); - }; - std::random_shuffle(reports.begin(), reports.end(), random_generator); + std::mt19937 urng(std::random_device{}()); + std::shuffle(reports.begin(), reports.end(), urng); std::vector<CrashReportDatabase::Report> pending_reports( reports.begin(), reports.begin() + 5); std::vector<CrashReportDatabase::Report> completed_reports( From 7198015c7318b056d20b2b0df275c604bb05989e Mon Sep 17 00:00:00 2001 From: Adam Kallai <kadam@inf.u-szeged.hu> Date: Fri, 24 Aug 2018 16:05:10 +0200 Subject: [PATCH 010/401] Fix the Chromium build on ChromeOS for aarch64 PTRACE_GET_THREAD_AREA is only removed from the newer version of glibc (>=2.28) for aarch64. Since ChromeOS uses 2.23 version of glibc currently, so it should be handled in crashpad to avoid the redefinition. BUG=chromium:873168 Change-Id: I8da6bc0595b814b0490b38da6f4a68e6803bb5b9 Reviewed-on: https://chromium-review.googlesource.com/1188309 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- compat/linux/sys/ptrace.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/linux/sys/ptrace.h b/compat/linux/sys/ptrace.h index c5e37a0f..f8be372c 100644 --- a/compat/linux/sys/ptrace.h +++ b/compat/linux/sys/ptrace.h @@ -26,7 +26,8 @@ static constexpr __ptrace_request PTRACE_GET_THREAD_AREA = static_cast<__ptrace_request>(25); #define PTRACE_GET_THREAD_AREA PTRACE_GET_THREAD_AREA -#elif defined(__arm__) || defined(__aarch64__) +// https://bugs.chromium.org/p/chromium/issues/detail?id=873168 +#elif defined(__arm__) || (defined(__aarch64__) && __GLIBC_PREREQ(2,28)) static constexpr __ptrace_request PTRACE_GET_THREAD_AREA = static_cast<__ptrace_request>(22); #define PTRACE_GET_THREAD_AREA PTRACE_GET_THREAD_AREA From 2c6c0935e226a723345fe584ec5d741590d7e49c Mon Sep 17 00:00:00 2001 From: Will Harris <wfh@chromium.org> Date: Wed, 22 Aug 2018 10:23:24 -0700 Subject: [PATCH 011/401] Fix an implicit 64-bit to 32-bit conversion. ../../third_party/crashpad/crashpad/util/misc/metrics.cc(66,35): error: implicit conversion loses integer precision: 'crashpad::FileOffset' (aka 'long long') to 'base::HistogramBase::Sample' (aka 'int') [-Werror,-Wshorten-64-to-32] "Crashpad.CrashReportSize", size, 0, 20 * 1024 * 1024, 50); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Also, remove some unneeded static_casts. BUG=588506 Change-Id: I0c12079db173e44c07e2f1d02322747cb2d69535 Reviewed-on: https://chromium-review.googlesource.com/1184227 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/misc/metrics.cc | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/util/misc/metrics.cc b/util/misc/metrics.cc index 7d191f71..bda90313 100644 --- a/util/misc/metrics.cc +++ b/util/misc/metrics.cc @@ -16,6 +16,7 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/numerics/safe_conversions.h" #include "build/build_config.h" #if defined(OS_MACOSX) @@ -55,43 +56,40 @@ void ExceptionProcessing(ExceptionProcessingState state) { // static void Metrics::CrashReportPending(PendingReportReason reason) { UMA_HISTOGRAM_ENUMERATION( - "Crashpad.CrashReportPending", - static_cast<int32_t>(reason), - static_cast<int32_t>(PendingReportReason::kMaxValue)); + "Crashpad.CrashReportPending", reason, PendingReportReason::kMaxValue); } // static void Metrics::CrashReportSize(FileOffset size) { - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Crashpad.CrashReportSize", size, 0, 20 * 1024 * 1024, 50); + UMA_HISTOGRAM_CUSTOM_COUNTS("Crashpad.CrashReportSize", + base::saturated_cast<uint32_t>(size), + 0, + 20 * 1024 * 1024, + 50); } // static void Metrics::CrashUploadAttempted(bool successful) { - UMA_HISTOGRAM_COUNTS("Crashpad.CrashUpload.AttemptSuccessful", - static_cast<int32_t>(successful)); + UMA_HISTOGRAM_COUNTS("Crashpad.CrashUpload.AttemptSuccessful", successful); } // static void Metrics::CrashUploadSkipped(CrashSkippedReason reason) { UMA_HISTOGRAM_ENUMERATION( - "Crashpad.CrashUpload.Skipped", - static_cast<int32_t>(reason), - static_cast<int32_t>(CrashSkippedReason::kMaxValue)); + "Crashpad.CrashUpload.Skipped", reason, CrashSkippedReason::kMaxValue); } // static void Metrics::ExceptionCaptureResult(CaptureResult result) { ExceptionProcessing(ExceptionProcessingState::kFinished); - UMA_HISTOGRAM_ENUMERATION("Crashpad.ExceptionCaptureResult", - static_cast<int32_t>(result), - static_cast<int32_t>(CaptureResult::kMaxValue)); + UMA_HISTOGRAM_ENUMERATION( + "Crashpad.ExceptionCaptureResult", result, CaptureResult::kMaxValue); } // static void Metrics::ExceptionCode(uint32_t exception_code) { base::UmaHistogramSparse("Crashpad.ExceptionCode." METRICS_OS_NAME, - static_cast<int32_t>(exception_code)); + exception_code); } // static @@ -102,15 +100,14 @@ void Metrics::ExceptionEncountered() { // static void Metrics::HandlerLifetimeMilestone(LifetimeMilestone milestone) { UMA_HISTOGRAM_ENUMERATION("Crashpad.HandlerLifetimeMilestone", - static_cast<int32_t>(milestone), - static_cast<int32_t>(LifetimeMilestone::kMaxValue)); + milestone, + LifetimeMilestone::kMaxValue); } // static void Metrics::HandlerCrashed(uint32_t exception_code) { base::UmaHistogramSparse( - "Crashpad.HandlerCrash.ExceptionCode." METRICS_OS_NAME, - static_cast<int32_t>(exception_code)); + "Crashpad.HandlerCrash.ExceptionCode." METRICS_OS_NAME, exception_code); } } // namespace crashpad From 255a4e0c0e51e4793432f26d0e430ad14586d4b4 Mon Sep 17 00:00:00 2001 From: Adam Norberg <norberg@chromium.org> Date: Thu, 23 Aug 2018 09:55:00 -0700 Subject: [PATCH 012/401] Add "external" dependency mode for Crashpad's GN build. This is required for repositories that do not use Crashpad's third_party/mini_chromium path because they have their own mini_chromium as a peer to Crashpad. Bug: crashpad: Change-Id: I5a765da75fb9efebc4ada17467371d51112fd391 Reviewed-on: https://chromium-review.googlesource.com/1185885 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- build/crashpad_buildconfig.gni | 36 +++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/build/crashpad_buildconfig.gni b/build/crashpad_buildconfig.gni index f767027f..7269d5f3 100644 --- a/build/crashpad_buildconfig.gni +++ b/build/crashpad_buildconfig.gni @@ -27,12 +27,14 @@ declare_args() { } } -assert( - crashpad_dependencies == "chromium" || crashpad_dependencies == "fuchsia" || - crashpad_dependencies == "standalone") +assert(crashpad_dependencies == "chromium" || + crashpad_dependencies == "fuchsia" || + crashpad_dependencies == "standalone" || + crashpad_dependencies == "external") crashpad_is_in_chromium = crashpad_dependencies == "chromium" crashpad_is_in_fuchsia = crashpad_dependencies == "fuchsia" +crashpad_is_external = crashpad_dependencies == "external" crashpad_is_standalone = crashpad_dependencies == "standalone" if (crashpad_is_in_chromium) { @@ -46,10 +48,16 @@ if (crashpad_is_in_chromium) { crashpad_is_clang = is_clang } else { - # Both standalone and in Fuchsia tree use mini_chromium, and it's mapped into - # the same location in both cases. - import("../third_party/mini_chromium/mini_chromium/build/compiler.gni") - import("../third_party/mini_chromium/mini_chromium/build/platform.gni") + # External builds assume crashpad and mini_chromium are peers. + if (crashpad_is_external) { + import("../../../mini_chromium/mini_chromium/build/compiler.gni") + import("../../../mini_chromium/mini_chromium/build/platform.gni") + } else { + # Both standalone and in Fuchsia tree use mini_chromium, and it's mapped into + # the same location in both cases. + import("../third_party/mini_chromium/mini_chromium/build/compiler.gni") + import("../third_party/mini_chromium/mini_chromium/build/platform.gni") + } crashpad_is_mac = mini_chromium_is_mac crashpad_is_win = mini_chromium_is_win crashpad_is_linux = mini_chromium_is_linux @@ -63,7 +71,12 @@ if (crashpad_is_in_chromium) { template("crashpad_executable") { executable(target_name) { - forward_variables_from(invoker, "*", [ "configs", "remove_configs" ]) + forward_variables_from(invoker, + "*", + [ + "configs", + "remove_configs", + ]) if (defined(invoker.remove_configs)) { configs -= invoker.remove_configs } @@ -86,7 +99,12 @@ template("crashpad_executable") { template("crashpad_loadable_module") { loadable_module(target_name) { - forward_variables_from(invoker, "*", [ "configs", "remove_configs" ]) + forward_variables_from(invoker, + "*", + [ + "configs", + "remove_configs", + ]) if (defined(invoker.remove_configs)) { configs -= invoker.remove_configs } From 8068e2dd6df7a4fe9bc35d90898ddf7eb9a2835e Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 23 Aug 2018 09:54:13 -0700 Subject: [PATCH 013/401] Remove references to exe_and_shlib_deps Upstreams: https://chromium-review.googlesource.com/c/chromium/src/+/1073613 Change-Id: Ieea63949eb4533061cf434157120a6e219897b6a Reviewed-on: https://chromium-review.googlesource.com/1187012 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- build/crashpad_buildconfig.gni | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/build/crashpad_buildconfig.gni b/build/crashpad_buildconfig.gni index 7269d5f3..bef534a2 100644 --- a/build/crashpad_buildconfig.gni +++ b/build/crashpad_buildconfig.gni @@ -85,13 +85,7 @@ template("crashpad_executable") { configs += invoker.configs } - if (!defined(deps)) { - deps = [] - } - - if (crashpad_is_in_chromium) { - deps += [ "//build/config:exe_and_shlib_deps" ] - } else if (crashpad_is_in_fuchsia) { + if (crashpad_is_in_fuchsia) { configs += [ "//build/config/fuchsia:fdio_config" ] } } @@ -113,13 +107,7 @@ template("crashpad_loadable_module") { configs += invoker.configs } - if (!defined(deps)) { - deps = [] - } - - if (crashpad_is_in_chromium) { - deps += [ "//build/config:exe_and_shlib_deps" ] - } else if (crashpad_is_in_fuchsia) { + if (crashpad_is_in_fuchsia) { configs += [ "//build/config/fuchsia:fdio_config" ] } } From 0204fbd38b729438a8fc2d5586df07141b3a3ea3 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 29 Aug 2018 07:28:10 -0700 Subject: [PATCH 014/401] posix: Make DoubleForkAndExec accept an envp parameter This will be useful to allow setting variables such as CLASSPATH or LD_LIBRARY_PATH without modifying or depending upon the application's current environment. Bug: crashpad:30 Change-Id: I34f31bcc397e51d789b48eb654d80f992a719074 Reviewed-on: https://chromium-review.googlesource.com/1194399 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_linux.cc | 2 +- client/crashpad_client_mac.cc | 1 + util/posix/double_fork_and_exec.cc | 19 +++++++++++++++++++ util/posix/double_fork_and_exec.h | 7 +++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 6a7c638c..ec5396f3 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -201,7 +201,7 @@ bool CrashpadClient::StartHandlerForClient( argv.push_back(FormatArgumentInt("initial-client-fd", socket)); - return DoubleForkAndExec(argv, 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 4a408206..22bd538c 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -338,6 +338,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface { // this interface. if (!DoubleForkAndExec( argv, + nullptr, server_write_fd.get(), true, restart ? CrashpadClient::UseSystemDefaultHandler : nullptr)) { diff --git a/util/posix/double_fork_and_exec.cc b/util/posix/double_fork_and_exec.cc index df74f709..e4ad9988 100644 --- a/util/posix/double_fork_and_exec.cc +++ b/util/posix/double_fork_and_exec.cc @@ -27,9 +27,12 @@ namespace crashpad { bool DoubleForkAndExec(const std::vector<std::string>& argv, + const std::vector<std::string>* 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 @@ -41,6 +44,15 @@ bool DoubleForkAndExec(const std::vector<std::string>& argv, } argv_c.push_back(nullptr); + std::vector<const char*> 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 @@ -102,6 +114,13 @@ bool DoubleForkAndExec(const std::vector<std::string>& argv, // const_cast is safe. char* const* argv_for_execv = const_cast<char* const*>(&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<char* const*>(&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]; diff --git a/util/posix/double_fork_and_exec.h b/util/posix/double_fork_and_exec.h index df340d07..02fc0f28 100644 --- a/util/posix/double_fork_and_exec.h +++ b/util/posix/double_fork_and_exec.h @@ -36,6 +36,9 @@ 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 +//! 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` @@ -49,6 +52,9 @@ namespace crashpad { //! 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. @@ -58,6 +64,7 @@ namespace crashpad { //! failures, for example, by observing a failure to perform a successful //! handshake with the grandchild process. bool DoubleForkAndExec(const std::vector<std::string>& argv, + const std::vector<std::string>* envp, int preserve_fd, bool use_path, void (*child_function)()); From d4d2f8557aac557743edc17b5501eb19c0463aee Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 29 Aug 2018 09:00:15 -0700 Subject: [PATCH 015/401] android: Add client methods to start a Java handler These methods use /system/bin/app_process{32,64} to load a Java class supplied by the embedding application. It is expected that the supplied class loads a native library containing Crashpad's handler code and passes its arguments to crashpad::HandlerMain(). Bug: crashpad:30 Change-Id: Ic0f9a1439007047b06f07f5ec7d5de9a9d4a19a2 Reviewed-on: https://chromium-review.googlesource.com/1194400 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/client_argv_handling.cc | 14 ++-- client/client_argv_handling.h | 10 +-- client/crashpad_client.h | 78 +++++++++++++++++++++++ client/crashpad_client_fuchsia.cc | 2 +- client/crashpad_client_linux.cc | 102 ++++++++++++++++++++++++++++-- 5 files changed, 189 insertions(+), 17 deletions(-) diff --git a/client/client_argv_handling.cc b/client/client_argv_handling.cc index 6933aac6..742a0008 100644 --- a/client/client_argv_handling.cc +++ b/client/client_argv_handling.cc @@ -61,14 +61,14 @@ std::vector<std::string> BuildHandlerArgvStrings( return argv_strings; } -void ConvertArgvStrings(const std::vector<std::string>& argv_strings, - std::vector<const char*>* argv) { - argv->clear(); - argv->reserve(argv_strings.size() + 1); - for (const auto& arg : argv_strings) { - argv->push_back(arg.c_str()); +void StringVectorToCStringVector(const std::vector<std::string>& strings, + std::vector<const char*>* c_strings) { + c_strings->clear(); + c_strings->reserve(strings.size() + 1); + for (const auto& str : strings) { + c_strings->push_back(str.c_str()); } - argv->push_back(nullptr); + c_strings->push_back(nullptr); } } // namespace crashpad diff --git a/client/client_argv_handling.h b/client/client_argv_handling.h index d380b1a0..04c66d31 100644 --- a/client/client_argv_handling.h +++ b/client/client_argv_handling.h @@ -40,11 +40,11 @@ std::vector<std::string> BuildHandlerArgvStrings( //! \brief Flattens a string vector into a const char* vector suitable for use //! in an exec() call. //! -//! \param[in] argv_strings Arguments to be passed to child process, typically -//! created by BuildHandlerArgvStrings(). -//! \param[out] argv argv suitable for starting the child process. -void ConvertArgvStrings(const std::vector<std::string>& argv_strings, - std::vector<const char*>* argv); +//! \param[in] strings A vector of string data. This vector must remain valid +//! for the lifetime of \a c_strings. +//! \param[out] c_strings A vector of pointers to the string data in \a strings. +void StringVectorToCStringVector(const std::vector<std::string>& strings, + std::vector<const char*>* c_strings); } // namespace crashpad diff --git a/client/crashpad_client.h b/client/crashpad_client.h index ae409d43..154d9ace 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -112,6 +112,84 @@ class CrashpadClient { bool restartable, bool asynchronous_start); +#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. + //! + //! \param[in] class_name The fully qualified class name to load, which must + //! define a `main()` method to be invoked by `app_process`. Arguments + //! will be passed to this method as though it were the Crashpad handler. + //! This class is expected to load a native library defining + //! crashpad::HandlerMain() and pass the arguments to it. + //! \param[in] env A vector of environment variables of the form `var=value` + //! defining the environment in which to execute `app_process`. If this + //! value is `nullptr`, the application's environment at the time of the + //! crash will be used. + //! \param[in] database The path to a Crashpad database. The handler will be + //! started with this path as its `--database` argument. + //! \param[in] metrics_dir The path to an already existing directory where + //! metrics files can be stored. The handler will be started with this + //! path as its `--metrics-dir` argument. + //! \param[in] url The URL of an upload server. The handler will be started + //! with this URL as its `--url` argument. + //! \param[in] annotations Process annotations to set in each crash report. + //! The handler will be started with an `--annotation` argument for each + //! element in this map. + //! \param[in] arguments Additional arguments to pass to the Crashpad handler. + //! Arguments passed in other parameters and arguments required to perform + //! the handshake are the responsibility of this method, and must not be + //! specified in this parameter. + //! + //! \return `true` on success, `false` on failure with a message logged. + static bool StartJavaHandlerAtCrash( + const std::string& class_name, + const std::vector<std::string>* env, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments); + + //! \brief Executes `/system/bin/app_process` and loads a Java class. + //! + //! \param[in] class_name The fully qualified class name to load, which must + //! define a `main()` method to be invoked by `app_process`. Arguments + //! will be passed to this method as though it were the Crashpad handler. + //! This class is expected to load a native library defining + //! crashpad::HandlerMain() and pass the arguments to it. + //! \param[in] env A vector of environment variables of the form `var=value` + //! defining the environment in which to execute `app_process`. If this + //! value is `nullptr`, the application's current environment will be + //! used. + //! \param[in] database The path to a Crashpad database. The handler will be + //! started with this path as its `--database` argument. + //! \param[in] metrics_dir The path to an already existing directory where + //! metrics files can be stored. The handler will be started with this + //! path as its `--metrics-dir` argument. + //! \param[in] url The URL of an upload server. The handler will be started + //! with this URL as its `--url` argument. + //! \param[in] annotations Process annotations to set in each crash report. + //! The handler will be started with an `--annotation` argument for each + //! element in this map. + //! \param[in] arguments Additional arguments to pass to the Crashpad handler. + //! Arguments passed in other parameters and arguments required to perform + //! the handshake are the responsibility of this method, and must not be + //! specified in this parameter. + //! \param[in] socket The server end of a socket pair. The client end should + //! be used with an ExceptionHandlerClient. + //! + //! \return `true` on success, `false` on failure with a message logged. + static bool StartJavaHandlerForClient( + const std::string& class_name, + const std::vector<std::string>* env, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments, + int socket); +#endif // OS_ANDROID || DOXYGEN + #if defined(OS_LINUX) || defined(OS_ANDROID) || DOXYGEN //! \brief Installs a signal handler to launch a handler process in reponse to //! a crash. diff --git a/client/crashpad_client_fuchsia.cc b/client/crashpad_client_fuchsia.cc index 0eba01d6..523a3e90 100644 --- a/client/crashpad_client_fuchsia.cc +++ b/client/crashpad_client_fuchsia.cc @@ -62,7 +62,7 @@ bool CrashpadClient::StartHandler( handler, database, metrics_dir, url, annotations, arguments); std::vector<const char*> argv; - ConvertArgvStrings(argv_strings, &argv); + StringVectorToCStringVector(argv_strings, &argv); // Follow the same protocol as devmgr and crashlogger in Zircon (that is, // process handle as handle 0, with type USER0, exception port handle as diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index ec5396f3..1e9d6518 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -45,6 +45,39 @@ std::string FormatArgumentAddress(const std::string& name, void* addr) { return base::StringPrintf("--%s=%p", name.c_str(), addr); } +#if defined(OS_ANDROID) + +std::vector<std::string> BuildAppProcessArgs( + const std::string& class_name, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments, + int socket) { + std::vector<std::string> argv; +#if defined(ARCH_CPU_64_BIT) + argv.push_back("/system/bin/app_process64"); +#else + argv.push_back("/system/bin/app_process32"); +#endif + argv.push_back("/system/bin"); + argv.push_back("--application"); + argv.push_back(class_name); + + std::vector<std::string> handler_argv = BuildHandlerArgvStrings( + base::FilePath(), database, metrics_dir, url, annotations, arguments); + + if (socket != kInvalidFileHandle) { + handler_argv.push_back(FormatArgumentInt("initial-client-fd", socket)); + } + + argv.insert(argv.end(), handler_argv.begin() + 1, handler_argv.end()); + return argv; +} + +#endif // OS_ANDROID + class SignalHandler { public: virtual void HandleCrashFatal(int signo, @@ -73,13 +106,20 @@ class LaunchAtCrashHandler : public SignalHandler { return instance; } - bool Initialize(std::vector<std::string>* argv_in) { + bool Initialize(std::vector<std::string>* argv_in, + const std::vector<std::string>* envp) { argv_strings_.swap(*argv_in); + if (envp) { + envp_strings_ = *envp; + StringVectorToCStringVector(envp_strings_, &envp_); + set_envp_ = true; + } + argv_strings_.push_back(FormatArgumentAddress("trace-parent-with-exception", &exception_information_)); - ConvertArgvStrings(argv_strings_, &argv_); + StringVectorToCStringVector(argv_strings_, &argv_); return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr); } @@ -107,7 +147,13 @@ class LaunchAtCrashHandler : public SignalHandler { return false; } if (pid == 0) { - execv(argv_[0], const_cast<char* const*>(argv_.data())); + if (set_envp_) { + execve(argv_[0], + const_cast<char* const*>(argv_.data()), + const_cast<char* const*>(envp_.data())); + } else { + execv(argv_[0], const_cast<char* const*>(argv_.data())); + } _exit(EXIT_FAILURE); } @@ -135,6 +181,9 @@ class LaunchAtCrashHandler : public SignalHandler { std::vector<std::string> argv_strings_; std::vector<const char*> argv_; + std::vector<std::string> envp_strings_; + std::vector<const char*> envp_; + bool set_envp_ = false; ExceptionInformation exception_information_; DISALLOW_COPY_AND_ASSIGN(LaunchAtCrashHandler); @@ -167,6 +216,51 @@ bool CrashpadClient::StartHandler( return false; } +#if defined(OS_ANDROID) + +// static +bool CrashpadClient::StartJavaHandlerAtCrash( + const std::string& class_name, + const std::vector<std::string>* env, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments) { + std::vector<std::string> argv = BuildAppProcessArgs(class_name, + database, + metrics_dir, + url, + annotations, + arguments, + kInvalidFileHandle); + + auto signal_handler = LaunchAtCrashHandler::Get(); + if (signal_handler->Initialize(&argv, env)) { + DCHECK(!g_crash_handler); + g_crash_handler = signal_handler; + return true; + } + return false; +} + +// static +bool CrashpadClient::StartJavaHandlerForClient( + const std::string& class_name, + const std::vector<std::string>* env, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments, + int socket) { + std::vector<std::string> argv = BuildAppProcessArgs( + class_name, database, metrics_dir, url, annotations, arguments, socket); + return DoubleForkAndExec(argv, env, socket, false, nullptr); +} + +#endif + // static bool CrashpadClient::StartHandlerAtCrash( const base::FilePath& handler, @@ -179,7 +273,7 @@ bool CrashpadClient::StartHandlerAtCrash( handler, database, metrics_dir, url, annotations, arguments); auto signal_handler = LaunchAtCrashHandler::Get(); - if (signal_handler->Initialize(&argv)) { + if (signal_handler->Initialize(&argv, nullptr)) { DCHECK(!g_crash_handler); g_crash_handler = signal_handler; return true; From 30b8c0dc2aff7acc22e563a2f7c8afa98ad742cc Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 29 Aug 2018 09:33:25 -0700 Subject: [PATCH 016/401] win: disable string_number_conversion_test for asan/dll Upstreams: https://chromium-review.googlesource.com/c/chromium/src/+/1113664 Change-Id: I8c3000eebf2be54e8d693bf08a6e92b68c1d5d72 Reviewed-on: https://chromium-review.googlesource.com/1195567 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/BUILD.gn | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/util/BUILD.gn b/util/BUILD.gn index bb15300b..ec8d1daf 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -15,6 +15,10 @@ import("../build/crashpad_buildconfig.gni") import("net/tls.gni") +if (crashpad_is_in_chromium) { + import("//build/config/sanitizers/sanitizers.gni") +} + if (crashpad_is_mac) { if (crashpad_is_in_chromium) { import("//build/config/sysroot.gni") @@ -639,6 +643,14 @@ source_set("util_test") { ] } + + if (crashpad_is_in_chromium) { + if (is_asan && is_component_build) { + # TODO(crbug.com/856174): Re-enable these once Windows ASan is fixed. + sources -= [ "stdlib/string_number_conversion_test.cc" ] + } + } + data = [ "net/testdata/", ] From a521447214beee644fba37d9999248563a799658 Mon Sep 17 00:00:00 2001 From: Maksim Sisov <msisov@igalia.com> Date: Fri, 7 Sep 2018 20:42:00 +0300 Subject: [PATCH 017/401] Use x30 register instead of LR, which GCC doesn't seem to understand When tested with GCC 6, it couldn't to understand LR register. Thus, use x30 instead. The error this patch fixes is the following: Error: operand 1 must be an integer register -- `str LR,[x0,#0x1b8]' Test: compile for aarch64 Change-Id: Icf1199254c6a29f72b6d2fa7940e1f33259a728b Reviewed-on: https://chromium-review.googlesource.com/1213125 Commit-Queue: Maksim Sisov <msisov@igalia.com> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- util/misc/capture_context_linux.S | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/misc/capture_context_linux.S b/util/misc/capture_context_linux.S index 42999a90..f2b066b7 100644 --- a/util/misc/capture_context_linux.S +++ b/util/misc/capture_context_linux.S @@ -263,10 +263,10 @@ CAPTURECONTEXT_SYMBOL2: str SP, [r0, #0x54] // context->uc_mcontext.sp // The original LR can't be recovered. - str LR, [r0, #0x58] // context->uc_mcontext.lr + str x30, [r0, #0x58] // context->uc_mcontext.lr // The link register holds the return address for this function. - str LR, [r0, #0x5c] // context->uc_mcontext.pc + str x30, [r0, #0x5c] // context->uc_mcontext.pc // Use r1 as a scratch register. @@ -312,14 +312,14 @@ CAPTURECONTEXT_SYMBOL2: stp x28, x29, [x0, #0x198] // The original LR can't be recovered. - str LR, [x0, #0x1a8] + 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. - str LR, [x0, #0x1b8] // context->uc_mcontext.pc + str x30, [x0, #0x1b8] // context->uc_mcontext.pc // NZCV, pstate, and CPSR are synonyms. mrs x1, NZCV From 78bf924fa63d14c50160f8a638c318aab3cd629a Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 10 Sep 2018 09:09:21 -0700 Subject: [PATCH 018/401] linux: Read /proc/<pid> files via PtraceConnection Bug: crashpad:250 Change-Id: I93c8944c48a17bd2c2b34cd9b8d81750cf80229c Reviewed-on: https://chromium-review.googlesource.com/1200311 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/linux/process_reader_linux.cc | 2 +- util/linux/proc_stat_reader.cc | 16 +++++----------- util/linux/proc_stat_reader.h | 6 ++++-- util/linux/proc_stat_reader_test.cc | 11 +++++++++-- util/posix/process_info.h | 1 + util/posix/process_info_linux.cc | 19 +++++++++++++------ 6 files changed, 33 insertions(+), 22 deletions(-) diff --git a/snapshot/linux/process_reader_linux.cc b/snapshot/linux/process_reader_linux.cc index 33d4f92b..43590116 100644 --- a/snapshot/linux/process_reader_linux.cc +++ b/snapshot/linux/process_reader_linux.cc @@ -236,7 +236,7 @@ bool ProcessReaderLinux::CPUTimes(timeval* user_time, for (const Thread& thread : threads_) { ProcStatReader stat; - if (!stat.Initialize(thread.tid)) { + if (!stat.Initialize(connection_, thread.tid)) { return false; } diff --git a/util/linux/proc_stat_reader.cc b/util/linux/proc_stat_reader.cc index b1dfe94f..795e5139 100644 --- a/util/linux/proc_stat_reader.cc +++ b/util/linux/proc_stat_reader.cc @@ -43,9 +43,12 @@ ProcStatReader::ProcStatReader() ProcStatReader::~ProcStatReader() {} -bool ProcStatReader::Initialize(pid_t tid) { +bool ProcStatReader::Initialize(PtraceConnection* connection, pid_t tid) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); - if (!ReadFile(tid)) { + + char path[32]; + snprintf(path, arraysize(path), "/proc/%d/stat", tid); + if (!connection->ReadFileContents(base::FilePath(path), &contents_)) { return false; } @@ -110,15 +113,6 @@ bool ProcStatReader::StartTime(timeval* start_time) const { return true; } -bool ProcStatReader::ReadFile(pid_t tid) { - char path[32]; - snprintf(path, arraysize(path), "/proc/%d/stat", tid); - if (!LoggingReadEntireFile(base::FilePath(path), &contents_)) { - return false; - } - return true; -} - bool ProcStatReader::FindColumn(int col_index, const char** column) const { size_t position = third_column_position_; for (int index = 2; index < col_index; ++index) { diff --git a/util/linux/proc_stat_reader.h b/util/linux/proc_stat_reader.h index 4cad97c5..c0b30520 100644 --- a/util/linux/proc_stat_reader.h +++ b/util/linux/proc_stat_reader.h @@ -22,6 +22,7 @@ #include <string> #include "base/macros.h" +#include "util/linux/ptrace_connection.h" #include "util/misc/initialization_state_dcheck.h" namespace crashpad { @@ -36,8 +37,10 @@ class ProcStatReader { //! //! This method must be successfully called before calling any other. //! + //! \param[in] connection A connection to the process to which the target + //! thread belongs. //! \param[in] tid The thread ID to read the stat file for. - bool Initialize(pid_t tid); + bool Initialize(PtraceConnection* connection, pid_t tid); //! \brief Determines the time the thread has spent executing in user mode. //! @@ -64,7 +67,6 @@ class ProcStatReader { bool StartTime(timeval* start_time) const; private: - bool ReadFile(pid_t tid); bool FindColumn(int index, const char** column) const; bool ReadTimeAtIndex(int index, timeval* time_val) const; diff --git a/util/linux/proc_stat_reader_test.cc b/util/linux/proc_stat_reader_test.cc index 8189c2ea..bc0d65bc 100644 --- a/util/linux/proc_stat_reader_test.cc +++ b/util/linux/proc_stat_reader_test.cc @@ -20,6 +20,7 @@ #include "base/logging.h" #include "gtest/gtest.h" +#include "test/linux/fake_ptrace_connection.h" #include "util/thread/thread.h" namespace crashpad { @@ -27,8 +28,11 @@ namespace test { namespace { TEST(ProcStatReader, Basic) { + FakePtraceConnection connection; + ASSERT_TRUE(connection.Initialize(getpid())); + ProcStatReader stat; - ASSERT_TRUE(stat.Initialize(getpid())); + ASSERT_TRUE(stat.Initialize(&connection, getpid())); timeval start_time; ASSERT_TRUE(stat.StartTime(&start_time)); @@ -53,8 +57,11 @@ pid_t gettid() { } void GetStartTime(timeval* start_time) { + FakePtraceConnection connection; + ASSERT_TRUE(connection.Initialize(getpid())); + ProcStatReader stat; - ASSERT_TRUE(stat.Initialize(gettid())); + ASSERT_TRUE(stat.Initialize(&connection, gettid())); ASSERT_TRUE(stat.StartTime(start_time)); } diff --git a/util/posix/process_info.h b/util/posix/process_info.h index 18a9cd93..7017cc64 100644 --- a/util/posix/process_info.h +++ b/util/posix/process_info.h @@ -174,6 +174,7 @@ class ProcessInfo { // multiple successive calls will always produce the same return value and out // parameters. This is necessary for intergration with the Snapshot interface. // See https://crashpad.chromium.org/bug/9. + PtraceConnection* connection_; std::set<gid_t> supplementary_groups_; mutable timeval start_time_; pid_t pid_; diff --git a/util/posix/process_info_linux.cc b/util/posix/process_info_linux.cc index 10c94b36..72a2bd70 100644 --- a/util/posix/process_info_linux.cc +++ b/util/posix/process_info_linux.cc @@ -20,13 +20,15 @@ #include "base/logging.h" #include "util/file/delimited_file_reader.h" #include "util/file/file_reader.h" +#include "util/file/string_file.h" #include "util/linux/proc_stat_reader.h" #include "util/misc/lexing.h" namespace crashpad { ProcessInfo::ProcessInfo() - : supplementary_groups_(), + : connection_(), + supplementary_groups_(), start_time_(), pid_(-1), ppid_(-1), @@ -45,16 +47,19 @@ bool ProcessInfo::InitializeWithPtrace(PtraceConnection* connection) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); DCHECK(connection); + connection_ = connection; pid_ = connection->GetProcessID(); is_64_bit_ = connection->Is64Bit(); { char path[32]; snprintf(path, sizeof(path), "/proc/%d/status", pid_); - FileReader status_file; - if (!status_file.Open(base::FilePath(path))) { + std::string contents; + if (!connection->ReadFileContents(base::FilePath(path), &contents)) { return false; } + StringFile status_file; + status_file.SetString(contents); DelimitedFileReader status_file_line_reader(&status_file); @@ -230,7 +235,7 @@ bool ProcessInfo::StartTime(timeval* start_time) const { if (start_time_initialized_.is_uninitialized()) { start_time_initialized_.set_invalid(); ProcStatReader reader; - if (!reader.Initialize(pid_)) { + if (!reader.Initialize(connection_, pid_)) { return false; } if (!reader.StartTime(&start_time_)) { @@ -252,10 +257,12 @@ bool ProcessInfo::Arguments(std::vector<std::string>* argv) const { char path[32]; snprintf(path, sizeof(path), "/proc/%d/cmdline", pid_); - FileReader cmdline_file; - if (!cmdline_file.Open(base::FilePath(path))) { + std::string contents; + if (!connection_->ReadFileContents(base::FilePath(path), &contents)) { return false; } + StringFile cmdline_file; + cmdline_file.SetString(contents); DelimitedFileReader cmdline_file_field_reader(&cmdline_file); From 9dcf4ab23efc121ca4993fdc1acce0c5e47a5b1c Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 10 Sep 2018 13:44:05 -0700 Subject: [PATCH 019/401] arm/linux: Fix build after a5214472 The build broke because x30 was used instead of r14 in place of LR which gcc doesn't recognize when building for 64-bit ARM. gcc does recognize LR for 32-bit ARM, however, so revert to that since it's more readable. Also, de-duplicate saving of FP/IP which are synonyms of r11/r12, saved above. Change-Id: I8ae28f430cc3c47f4e4cf3679383ed5b94fadd2e Reviewed-on: https://chromium-review.googlesource.com/1217483 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/misc/capture_context_linux.S | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/util/misc/capture_context_linux.S b/util/misc/capture_context_linux.S index f2b066b7..f4216fd1 100644 --- a/util/misc/capture_context_linux.S +++ b/util/misc/capture_context_linux.S @@ -257,16 +257,14 @@ CAPTURECONTEXT_SYMBOL2: // Restore r0. sub r0, r0, #0x24 - // Save named general purpose registers. - str FP, [r0, #0x4c] // context->uc_mcontext.fp - str IP, [r0, #0x50] // context->uc_mcontext.ip + // Save SP/r13. str SP, [r0, #0x54] // context->uc_mcontext.sp // The original LR can't be recovered. - str x30, [r0, #0x58] // context->uc_mcontext.lr + str LR, [r0, #0x58] // context->uc_mcontext.lr // The link register holds the return address for this function. - str x30, [r0, #0x5c] // context->uc_mcontext.pc + str LR, [r0, #0x5c] // context->uc_mcontext.pc // Use r1 as a scratch register. From b918119ca20a4b5c2b4a1a7dc59690944bce1140 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 11 Sep 2018 14:20:03 -0700 Subject: [PATCH 020/401] linux: Read thread IDs via a PtraceConnection Bug: crashpad:250 Change-Id: I2ff9c2d810f7af25f7438e974e0adfb5abebec16 Reviewed-on: https://chromium-review.googlesource.com/1200962 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/linux/process_reader_linux.cc | 26 ++------ test/linux/fake_ptrace_connection.cc | 6 ++ test/linux/fake_ptrace_connection.h | 3 + util/linux/direct_ptrace_connection.cc | 37 +++++++++++ util/linux/direct_ptrace_connection.h | 1 + util/linux/ptrace_broker.cc | 57 ++++++++++++++++- util/linux/ptrace_broker.h | 15 ++++- util/linux/ptrace_broker_test.cc | 11 ++++ util/linux/ptrace_client.cc | 88 ++++++++++++++++++++++++++ util/linux/ptrace_client.h | 1 + util/linux/ptrace_connection.h | 9 +++ 11 files changed, 228 insertions(+), 26 deletions(-) diff --git a/snapshot/linux/process_reader_linux.cc b/snapshot/linux/process_reader_linux.cc index 43590116..1e0550d2 100644 --- a/snapshot/linux/process_reader_linux.cc +++ b/snapshot/linux/process_reader_linux.cc @@ -17,7 +17,6 @@ #include <elf.h> #include <errno.h> #include <sched.h> -#include <stdio.h> #include <string.h> #include <sys/resource.h> #include <unistd.h> @@ -25,13 +24,10 @@ #include <algorithm> #include "base/logging.h" -#include "base/strings/string_number_conversions.h" #include "build/build_config.h" #include "snapshot/linux/debug_rendezvous.h" -#include "util/file/directory_reader.h" #include "util/linux/auxiliary_vector.h" #include "util/linux/proc_stat_reader.h" -#include "util/misc/as_underlying_type.h" namespace crashpad { @@ -298,23 +294,11 @@ void ProcessReaderLinux::InitializeThreads() { LOG(WARNING) << "Couldn't initialize main thread."; } - char path[32]; - snprintf(path, arraysize(path), "/proc/%d/task", pid); bool main_thread_found = false; - DirectoryReader reader; - if (!reader.Open(base::FilePath(path))) { - return; - } - base::FilePath tid_str; - DirectoryReader::Result result; - while ((result = reader.NextFile(&tid_str)) == - DirectoryReader::Result::kSuccess) { - pid_t tid; - if (!base::StringToInt(tid_str.value(), &tid)) { - LOG(ERROR) << "format error"; - continue; - } - + std::vector<pid_t> thread_ids; + bool result = connection_->Threads(&thread_ids); + DCHECK(result); + for (pid_t tid : thread_ids) { if (tid == pid) { DCHECK(!main_thread_found); main_thread_found = true; @@ -328,8 +312,6 @@ void ProcessReaderLinux::InitializeThreads() { threads_.push_back(thread); } } - DCHECK_EQ(AsUnderlyingType(result), - AsUnderlyingType(DirectoryReader::Result::kNoMoreFiles)); DCHECK(main_thread_found); } diff --git a/test/linux/fake_ptrace_connection.cc b/test/linux/fake_ptrace_connection.cc index 022b1327..b03228a2 100644 --- a/test/linux/fake_ptrace_connection.cc +++ b/test/linux/fake_ptrace_connection.cc @@ -92,5 +92,11 @@ ProcessMemory* FakePtraceConnection::Memory() { return memory_.get(); } +bool FakePtraceConnection::Threads(std::vector<pid_t>* threads) { + // TODO(jperaza): Implement this if/when it's needed. + NOTREACHED(); + return false; +} + } // namespace test } // namespace crashpad diff --git a/test/linux/fake_ptrace_connection.h b/test/linux/fake_ptrace_connection.h index 6597c473..01a6f925 100644 --- a/test/linux/fake_ptrace_connection.h +++ b/test/linux/fake_ptrace_connection.h @@ -62,6 +62,9 @@ class FakePtraceConnection : public PtraceConnection { //! ADD_FAILURE() and returning `nullptr` on failure. ProcessMemory* Memory() override; + //! \todo Not yet implemented. + bool Threads(std::vector<pid_t>* threads) override; + private: std::set<pid_t> attachments_; std::unique_ptr<ProcessMemoryLinux> memory_; diff --git a/util/linux/direct_ptrace_connection.cc b/util/linux/direct_ptrace_connection.cc index a3df425f..ac44bf13 100644 --- a/util/linux/direct_ptrace_connection.cc +++ b/util/linux/direct_ptrace_connection.cc @@ -14,9 +14,15 @@ #include "util/linux/direct_ptrace_connection.h" +#include <stdio.h> + #include <utility> +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "util/file/directory_reader.h" #include "util/file/file_io.h" +#include "util/misc/as_underlying_type.h" namespace crashpad { @@ -81,4 +87,35 @@ ProcessMemory* DirectPtraceConnection::Memory() { return &memory_; } +bool DirectPtraceConnection::Threads(std::vector<pid_t>* threads) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + DCHECK(threads->empty()); + + char path[32]; + snprintf(path, arraysize(path), "/proc/%d/task", pid_); + DirectoryReader reader; + if (!reader.Open(base::FilePath(path))) { + return false; + } + + std::vector<pid_t> local_threads; + base::FilePath tid_str; + DirectoryReader::Result result; + while ((result = reader.NextFile(&tid_str)) == + DirectoryReader::Result::kSuccess) { + pid_t tid; + if (!base::StringToInt(tid_str.value(), &tid)) { + LOG(ERROR) << "format error"; + continue; + } + + local_threads.push_back(tid); + } + DCHECK_EQ(AsUnderlyingType(result), + AsUnderlyingType(DirectoryReader::Result::kNoMoreFiles)); + + threads->swap(local_threads); + return true; +} + } // namespace crashpad diff --git a/util/linux/direct_ptrace_connection.h b/util/linux/direct_ptrace_connection.h index 53594ef9..10f8370c 100644 --- a/util/linux/direct_ptrace_connection.h +++ b/util/linux/direct_ptrace_connection.h @@ -56,6 +56,7 @@ class DirectPtraceConnection : public PtraceConnection { bool ReadFileContents(const base::FilePath& path, std::string* contents) override; ProcessMemory* Memory() override; + bool Threads(std::vector<pid_t>* threads) override; private: std::vector<std::unique_ptr<ScopedPtraceAttach>> attachments_; diff --git a/util/linux/ptrace_broker.cc b/util/linux/ptrace_broker.cc index e9d30686..4d7e4ced 100644 --- a/util/linux/ptrace_broker.cc +++ b/util/linux/ptrace_broker.cc @@ -17,6 +17,7 @@ #include <fcntl.h> #include <limits.h> #include <string.h> +#include <syscall.h> #include <unistd.h> #include <algorithm> @@ -192,7 +193,9 @@ int PtraceBroker::RunImpl() { case Request::kTypeReadFile: { ScopedFileHandle handle; - int result = ReceiveAndOpenFilePath(request.path.path_length, &handle); + int result = ReceiveAndOpenFilePath(request.path.path_length, + /* is_directory= */ false, + &handle); if (result != 0) { return result; } @@ -217,6 +220,26 @@ int PtraceBroker::RunImpl() { continue; } + case Request::kTypeListDirectory: { + ScopedFileHandle handle; + int result = ReceiveAndOpenFilePath(request.path.path_length, + /* is_directory= */ true, + &handle); + if (result != 0) { + return result; + } + + if (!handle.is_valid()) { + continue; + } + + result = SendDirectory(handle.get()); + if (result != 0) { + return result; + } + continue; + } + case Request::kTypeExit: return 0; } @@ -329,7 +352,32 @@ int PtraceBroker::SendMemory(pid_t pid, VMAddress address, VMSize size) { return 0; } +int PtraceBroker::SendDirectory(FileHandle handle) { + char buffer[4096]; + int rv; + do { + rv = syscall(SYS_getdents64, handle, buffer, sizeof(buffer)); + + if (rv < 0) { + return SendReadError(static_cast<ReadError>(errno)); + } + + if (!WriteFile(sock_, &rv, sizeof(rv))) { + return errno; + } + + if (rv > 0) { + if (!WriteFile(sock_, buffer, static_cast<size_t>(rv))) { + return errno; + } + } + } while (rv > 0); + + return 0; +} + int PtraceBroker::ReceiveAndOpenFilePath(VMSize path_length, + bool is_directory, ScopedFileHandle* handle) { char path[std::max(4096, PATH_MAX)]; @@ -346,8 +394,11 @@ int PtraceBroker::ReceiveAndOpenFilePath(VMSize path_length, return SendOpenResult(kOpenResultAccessDenied); } - ScopedFileHandle local_handle( - HANDLE_EINTR(open(path, O_RDONLY | O_CLOEXEC | O_NOCTTY))); + int flags = O_RDONLY | O_CLOEXEC | O_NOCTTY; + if (is_directory) { + flags |= O_DIRECTORY; + } + ScopedFileHandle local_handle(HANDLE_EINTR(open(path, flags))); if (!local_handle.is_valid()) { return SendOpenResult(static_cast<OpenResult>(errno)); } diff --git a/util/linux/ptrace_broker.h b/util/linux/ptrace_broker.h index 2e5decdf..47dd4d9b 100644 --- a/util/linux/ptrace_broker.h +++ b/util/linux/ptrace_broker.h @@ -75,6 +75,16 @@ class PtraceBroker { //! errors, followed by an Errno. On success, the bytes read follow. kTypeReadFile, + //! \brief Reads the contents of a directory. The data is returned in a + //! series of messages. The first message is an OpenResult, indicating + //! the validity of the received file path. If the OpenResult is + //! kOpenResultSuccess, the subsequent messages return the contents of + //! the directory as a dirent stream, as read by `getdents64()`. Each + //! subsequent message begins with an int32_t indicating the number of + //! bytes read, 0 for end-of-file, or -1 for errors, followed by an + //! Errno. On success, the bytes read follow. + kTypeListDirectory, + //! \brief Causes the broker to return from Run(), detaching all attached //! threads. Does not respond. kTypeExit @@ -190,9 +200,12 @@ class PtraceBroker { int SendReadError(ReadError err); int SendOpenResult(OpenResult result); int SendFileContents(FileHandle handle); + int SendDirectory(FileHandle handle); void TryOpeningMemFile(); int SendMemory(pid_t pid, VMAddress address, VMSize size); - int ReceiveAndOpenFilePath(VMSize path_length, ScopedFileHandle* handle); + int ReceiveAndOpenFilePath(VMSize path_length, + bool is_directory, + ScopedFileHandle* handle); char file_root_buffer_[32]; Ptracer ptracer_; diff --git a/util/linux/ptrace_broker_test.cc b/util/linux/ptrace_broker_test.cc index 9ed1973b..341f2c80 100644 --- a/util/linux/ptrace_broker_test.cc +++ b/util/linux/ptrace_broker_test.cc @@ -155,6 +155,17 @@ class SameBitnessTest : public Multiprocess { client_sock.get(), ChildPID(), /* try_direct_memory= */ false)); EXPECT_EQ(client.GetProcessID(), ChildPID()); + + std::vector<pid_t> threads; + ASSERT_TRUE(client.Threads(&threads)); + EXPECT_EQ(threads.size(), 2u); + if (threads[0] == ChildPID()) { + EXPECT_EQ(threads[1], child2_tid); + } else { + EXPECT_EQ(threads[0], child2_tid); + EXPECT_EQ(threads[1], ChildPID()); + } + EXPECT_TRUE(client.Attach(child2_tid)); EXPECT_EQ(client.Is64Bit(), am_64_bit); diff --git a/util/linux/ptrace_client.cc b/util/linux/ptrace_client.cc index b5ccebaf..aa3e0244 100644 --- a/util/linux/ptrace_client.cc +++ b/util/linux/ptrace_client.cc @@ -20,6 +20,7 @@ #include <string> #include "base/logging.h" +#include "base/strings/string_number_conversions.h" #include "util/file/file_io.h" #include "util/linux/ptrace_broker.h" #include "util/process/process_memory_linux.h" @@ -80,6 +81,48 @@ bool AttachImpl(int sock, pid_t tid) { return true; } +struct Dirent64 { + ino64_t d_ino; + off64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[]; +}; + +void ReadDentsAsThreadIDs(char* buffer, + size_t size, + std::vector<pid_t>* threads) { + while (size > sizeof(Dirent64)) { + auto dirent = reinterpret_cast<Dirent64*>(buffer); + if (size < dirent->d_reclen) { + LOG(ERROR) << "short dirent"; + break; + } + buffer += dirent->d_reclen; + size -= dirent->d_reclen; + + const size_t max_name_length = + dirent->d_reclen - offsetof(Dirent64, d_name); + size_t name_len = strnlen(dirent->d_name, max_name_length); + if (name_len >= max_name_length) { + LOG(ERROR) << "format error"; + break; + } + + if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) { + continue; + } + + pid_t tid; + if (!base::StringToInt(dirent->d_name, &tid)) { + LOG(ERROR) << "format error"; + continue; + } + threads->push_back(tid); + } + DCHECK_EQ(size, 0u); +} + } // namespace PtraceClient::PtraceClient() @@ -218,6 +261,51 @@ ProcessMemory* PtraceClient::Memory() { return memory_.get(); } +bool PtraceClient::Threads(std::vector<pid_t>* threads) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + DCHECK(threads->empty()); + + // If the broker is unable to read thread IDs, fall-back to just the main + // thread's ID. + threads->push_back(pid_); + + char path[32]; + snprintf(path, arraysize(path), "/proc/%d/task", pid_); + + PtraceBroker::Request request; + request.type = PtraceBroker::Request::kTypeListDirectory; + request.path.path_length = strlen(path); + + if (!LoggingWriteFile(sock_, &request, sizeof(request)) || + !SendFilePath(path, request.path.path_length)) { + return false; + } + + std::vector<pid_t> local_threads; + int32_t read_result; + do { + if (!LoggingReadFileExactly(sock_, &read_result, sizeof(read_result))) { + return false; + } + + if (read_result < 0) { + return ReceiveAndLogReadError(sock_, "Threads"); + } + + if (read_result > 0) { + auto buffer = std::make_unique<char[]>(read_result); + if (!LoggingReadFileExactly(sock_, buffer.get(), read_result)) { + return false; + } + + ReadDentsAsThreadIDs(buffer.get(), read_result, &local_threads); + } + } while (read_result > 0); + + threads->swap(local_threads); + return true; +} + PtraceClient::BrokeredMemory::BrokeredMemory(PtraceClient* client) : ProcessMemory(), client_(client) {} diff --git a/util/linux/ptrace_client.h b/util/linux/ptrace_client.h index a7abc0cf..b4f27ae7 100644 --- a/util/linux/ptrace_client.h +++ b/util/linux/ptrace_client.h @@ -61,6 +61,7 @@ class PtraceClient : public PtraceConnection { bool ReadFileContents(const base::FilePath& path, std::string* contents) override; ProcessMemory* Memory() override; + bool Threads(std::vector<pid_t>* threads) override; private: class BrokeredMemory : public ProcessMemory { diff --git a/util/linux/ptrace_connection.h b/util/linux/ptrace_connection.h index 86dc2dd9..21117475 100644 --- a/util/linux/ptrace_connection.h +++ b/util/linux/ptrace_connection.h @@ -18,6 +18,7 @@ #include <sys/types.h> #include <string> +#include <vector> #include "base/files/file_path.h" #include "util/linux/thread_info.h" @@ -64,6 +65,14 @@ class PtraceConnection { //! The caller does not take ownership of the reader. The reader is valid for //! the lifetime of the PtraceConnection that created it. virtual ProcessMemory* Memory() = 0; + + //! \brief Determines the thread IDs of the threads in the connected process. + //! + //! \param[out] threads The list of thread IDs. + //! \return `true` on success, `false` on failure with a message logged. If + //! this method returns `false`, \a threads may contain a partial list of + //! thread IDs. + virtual bool Threads(std::vector<pid_t>* threads) = 0; }; } // namespace crashpad From 076d760d636a5a4af6721f04ebcd7389f703704c Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 14 Sep 2018 09:37:12 -0700 Subject: [PATCH 021/401] linux: Check for SO_PASSCRED on client sockets before setting Bug: crashpad:252 Change-Id: I742fc8923a8497fe83dc40a4a280217ffc691ae7 Reviewed-on: https://chromium-review.googlesource.com/1226115 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- handler/linux/exception_handler_server.cc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index 748bf6e9..71a5dc74 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -307,12 +307,25 @@ void ExceptionHandlerServer::HandleEvent(Event* event, uint32_t event_type) { } bool ExceptionHandlerServer::InstallClientSocket(ScopedFileHandle socket) { - int optval = 1; + // The handler may not have permission to set SO_PASSCRED on the socket, but + // it doesn't need to if the client has already set it. + // https://bugs.chromium.org/p/crashpad/issues/detail?id=252 + int optval; socklen_t optlen = sizeof(optval); - if (setsockopt(socket.get(), SOL_SOCKET, SO_PASSCRED, &optval, optlen) != 0) { - PLOG(ERROR) << "setsockopt"; + if (getsockopt(socket.get(), SOL_SOCKET, SO_PASSCRED, &optval, &optlen) != + 0) { + PLOG(ERROR) << "getsockopt"; return false; } + if (!optval) { + optval = 1; + optlen = sizeof(optval); + if (setsockopt(socket.get(), SOL_SOCKET, SO_PASSCRED, &optval, optlen) != + 0) { + PLOG(ERROR) << "setsockopt"; + return false; + } + } auto event = std::make_unique<Event>(); event->type = Event::Type::kClientMessage; From 8595f4b4231d82284c877b54463952a68d209fd4 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 14 Sep 2018 09:29:27 -0700 Subject: [PATCH 022/401] linux: allow collecting scheduler priorities to fail SELinux blocks the handler from collecting these values on Android M. They should eventually be collected via the broker. Change-Id: Iad47759b2ebf23148cb5b2c401241ee87f8ffd27 Reviewed-on: https://chromium-review.googlesource.com/1226120 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/linux/process_reader_linux.cc | 17 +- snapshot/linux/process_reader_linux.h | 4 + snapshot/linux/thread_snapshot_linux.cc | 211 +++++++++++++----------- 3 files changed, 127 insertions(+), 105 deletions(-) diff --git a/snapshot/linux/process_reader_linux.cc b/snapshot/linux/process_reader_linux.cc index 1e0550d2..7a3e6092 100644 --- a/snapshot/linux/process_reader_linux.cc +++ b/snapshot/linux/process_reader_linux.cc @@ -60,31 +60,36 @@ bool ProcessReaderLinux::Thread::InitializePtrace( return false; } + // TODO(jperaza): Collect scheduling priorities via the broker when they can't + // be collected directly. + have_priorities = false; + // TODO(jperaza): Starting with Linux 3.14, scheduling policy, static // priority, and nice value can be collected all in one call with // sched_getattr(). int res = sched_getscheduler(tid); if (res < 0) { - PLOG(ERROR) << "sched_getscheduler"; - return false; + PLOG(WARNING) << "sched_getscheduler"; + return true; } sched_policy = res; sched_param param; if (sched_getparam(tid, ¶m) != 0) { - PLOG(ERROR) << "sched_getparam"; - return false; + PLOG(WARNING) << "sched_getparam"; + return true; } static_priority = param.sched_priority; errno = 0; res = getpriority(PRIO_PROCESS, tid); if (res == -1 && errno) { - PLOG(ERROR) << "getpriority"; - return false; + PLOG(WARNING) << "getpriority"; + return true; } nice_value = res; + have_priorities = true; return true; } diff --git a/snapshot/linux/process_reader_linux.h b/snapshot/linux/process_reader_linux.h index 7c17d9d1..dbe436a6 100644 --- a/snapshot/linux/process_reader_linux.h +++ b/snapshot/linux/process_reader_linux.h @@ -66,6 +66,10 @@ class ProcessReaderLinux { int static_priority; int nice_value; + //! \brief `true` if `sched_policy`, `static_priority`, and `nice_value` are + //! all valid. + bool have_priorities; + private: friend class ProcessReaderLinux; diff --git a/snapshot/linux/thread_snapshot_linux.cc b/snapshot/linux/thread_snapshot_linux.cc index 8ffbfe8b..f40c78e8 100644 --- a/snapshot/linux/thread_snapshot_linux.cc +++ b/snapshot/linux/thread_snapshot_linux.cc @@ -23,6 +23,109 @@ namespace crashpad { namespace internal { +namespace { + +int ComputeThreadPriority(int static_priority, + int sched_policy, + int nice_value) { + // Map Linux scheduling policy, static priority, and nice value into a + // single int value. + // + // The possible policies in order of approximate priority (low to high) are + // SCHED_IDLE + // SCHED_BATCH + // SCHED_OTHER + // SCHED_RR + // SCHED_FIFO + // + // static_priority is not used for OTHER, BATCH, or IDLE and should be 0. + // For FIFO and RR, static_priority should range from 1 to 99 with 99 being + // the highest priority. + // + // nice value ranges from -20 to 19, with -20 being highest priority + + enum class Policy : uint8_t { + kUnknown = 0, + kIdle, + kBatch, + kOther, + kRR, + kFIFO + }; + + struct LinuxPriority { +#if defined(ARCH_CPU_LITTLE_ENDIAN) + // nice values affect how dynamic priorities are updated, which only + // matters for threads with the same static priority. + uint8_t nice_value = 0; + + // The scheduling policy also affects how threads with the same static + // priority are ordered, but has greater impact than nice value. + Policy policy = Policy::kUnknown; + + // The static priority is the most significant in determining overall + // priority. + uint8_t static_priority = 0; + + // Put this in the most significant byte position to prevent negative + // priorities. + uint8_t unused = 0; +#elif defined(ARCH_CPU_BIG_ENDIAN) + uint8_t unused = 0; + uint8_t static_priority = 0; + Policy policy = Policy::kUnknown; + uint8_t nice_value = 0; +#endif // ARCH_CPU_LITTLE_ENDIAN + }; + static_assert(sizeof(LinuxPriority) <= sizeof(int), "priority is too large"); + + LinuxPriority prio; + + // Lower nice values have higher priority, so negate them and add 20 to put + // them in the range 1-40 with 40 being highest priority. + if (nice_value < -20 || nice_value > 19) { + LOG(WARNING) << "invalid nice value " << nice_value; + prio.nice_value = 0; + } else { + prio.nice_value = -1 * nice_value + 20; + } + + switch (sched_policy) { + case SCHED_IDLE: + prio.policy = Policy::kIdle; + break; + case SCHED_BATCH: + prio.policy = Policy::kBatch; + break; + case SCHED_OTHER: + prio.policy = Policy::kOther; + break; + case SCHED_RR: + prio.policy = Policy::kRR; + break; + case SCHED_FIFO: + prio.policy = Policy::kFIFO; + break; + default: + prio.policy = Policy::kUnknown; + LOG(WARNING) << "Unknown scheduling policy " << sched_policy; + } + + if (static_priority < 0 || static_priority > 99) { + LOG(WARNING) << "invalid static priority " << static_priority; + } + prio.static_priority = static_priority; + + int priority; + if (!ReinterpretBytes(prio, &priority)) { + LOG(ERROR) << "Couldn't set priority"; + return -1; + } + return priority; +} + +} // namespace + ThreadSnapshotLinux::ThreadSnapshotLinux() : ThreadSnapshot(), context_union_(), @@ -31,11 +134,9 @@ ThreadSnapshotLinux::ThreadSnapshotLinux() thread_specific_data_address_(0), thread_id_(-1), priority_(-1), - initialized_() { -} + initialized_() {} -ThreadSnapshotLinux::~ThreadSnapshotLinux() { -} +ThreadSnapshotLinux::~ThreadSnapshotLinux() {} bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, const ProcessReaderLinux::Thread& thread) { @@ -89,107 +190,19 @@ bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, #error Port. #endif - stack_.Initialize(process_reader, - thread.stack_region_address, - thread.stack_region_size); + stack_.Initialize( + process_reader, thread.stack_region_address, thread.stack_region_size); thread_specific_data_address_ = thread.thread_info.thread_specific_data_address; thread_id_ = thread.tid; - // Map Linux scheduling policy, static priority, and nice value into a single - // int value. - // - // The possible policies in order of approximate priority (low to high) are - // SCHED_IDLE - // SCHED_BATCH - // SCHED_OTHER - // SCHED_RR - // SCHED_FIFO - // - // static_priority is not used for OTHER, BATCH, or IDLE and should be 0. - // For FIFO and RR, static_priority should range from 1 to 99 with 99 being - // the highest priority. - // - // nice value ranges from -20 to 19, with -20 being highest priority - - enum class Policy : uint8_t { - kUnknown = 0, - kIdle, - kBatch, - kOther, - kRR, - kFIFO - }; - - struct LinuxPriority { -#if defined(ARCH_CPU_LITTLE_ENDIAN) - // nice values affect how dynamic priorities are updated, which only matters - // for threads with the same static priority. - uint8_t nice_value = 0; - - // The scheduling policy also affects how threads with the same static - // priority are ordered, but has greater impact than nice value. - Policy policy = Policy::kUnknown; - - // The static priority is the most significant in determining overall - // priority. - uint8_t static_priority = 0; - - // Put this in the most significant byte position to prevent negative - // priorities. - uint8_t unused = 0; -#elif defined(ARCH_CPU_BIG_ENDIAN) - uint8_t unused = 0; - uint8_t static_priority = 0; - Policy policy = Policy::kUnknown; - uint8_t nice_value = 0; -#endif // ARCH_CPU_LITTLE_ENDIAN - }; - static_assert(sizeof(LinuxPriority) <= sizeof(int), "priority is too large"); - - LinuxPriority prio; - - // Lower nice values have higher priority, so negate them and add 20 to put - // them in the range 1-40 with 40 being highest priority. - if (thread.nice_value < -20 || thread.nice_value > 19) { - LOG(WARNING) << "invalid nice value " << thread.nice_value; - prio.nice_value = 0; - } else { - prio.nice_value = -1 * thread.nice_value + 20; - } - - switch (thread.sched_policy) { - case SCHED_IDLE: - prio.policy = Policy::kIdle; - break; - case SCHED_BATCH: - prio.policy = Policy::kBatch; - break; - case SCHED_OTHER: - prio.policy = Policy::kOther; - break; - case SCHED_RR: - prio.policy = Policy::kRR; - break; - case SCHED_FIFO: - prio.policy = Policy::kFIFO; - break; - default: - prio.policy = Policy::kUnknown; - LOG(WARNING) << "Unknown scheduling policy " << thread.sched_policy; - } - - if (thread.static_priority < 0 || thread.static_priority > 99) { - LOG(WARNING) << "invalid static priority " << thread.static_priority; - } - prio.static_priority = thread.static_priority; - - if (!ReinterpretBytes(prio, &priority_)) { - LOG(ERROR) << "Couldn't set priority"; - return false; - } + priority_ = + thread.have_priorities + ? ComputeThreadPriority( + thread.static_priority, thread.sched_policy, thread.nice_value) + : -1; INITIALIZATION_STATE_SET_VALID(initialized_); return true; From 9ae453628f50a5c23ac6ecf621edfc06344b5e21 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 20 Sep 2018 09:16:22 -0700 Subject: [PATCH 023/401] android: handle RELRO sharing by the Chromium linker Bug: crashpad:253 Change-Id: I7d6b1bfebe621d90a4b69dd44073abf471fa822c Reviewed-on: https://chromium-review.googlesource.com/1232293 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/linux/memory_map.cc | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index 345f63ca..ea33f300 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -316,6 +316,37 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts( return std::vector<const Mapping*>(); } +#if defined(OS_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:<libname>" where <libname> is the base + // library name (e.g. libchrome.so) sans any preceding path that may be + // present in other mappings for the library. + // https://crashpad.chromium.org/bug/253 + static constexpr char kRelro[] = "/dev/ashmem/RELRO:"; + if (mapping.name.compare(0, strlen(kRelro), kRelro, 0, strlen(kRelro)) == 0) { + // The kernel appends "(deleted)" to ashmem mappings because there isn't + // any corresponding file on the filesystem. + static constexpr char kDeleted[] = " (deleted)"; + size_t libname_end = mapping.name.rfind(kDeleted); + DCHECK_NE(libname_end, std::string::npos); + if (libname_end == std::string::npos) { + libname_end = mapping.name.size(); + } + + std::string libname = + mapping.name.substr(strlen(kRelro), libname_end - strlen(kRelro)); + for (const auto& candidate : mappings_) { + if (candidate.name.rfind(libname) != std::string::npos) { + possible_starts.push_back(&candidate); + } + if (mapping.Equals(candidate)) { + return possible_starts; + } + } + } +#endif // OS_ANDROID + for (const auto& candidate : mappings_) { if (candidate.device == mapping.device && candidate.inode == mapping.inode && From 688dcfa22ee906f83d49b905b69c7c53347c92d9 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 20 Sep 2018 10:13:58 -0700 Subject: [PATCH 024/401] android: handle modules loaded from zipfiles Modules mapped from zipfiles will have mappings named for the zipfile rather than the module name and an offset into that zipfile instead of 0. Bug: crashpad:253, crashpad:254 Change-Id: I0503d13e7b80ba7bd1cc2d241633d9c68c98f1cd Reviewed-on: https://chromium-review.googlesource.com/1232294 Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/elf/elf_image_reader.cc | 14 +++++++++++ snapshot/elf/elf_image_reader.h | 7 ++++++ snapshot/linux/process_reader_linux.cc | 7 +++++- util/linux/memory_map.cc | 9 +++++-- util/linux/memory_map.h | 13 +++++++--- util/linux/memory_map_test.cc | 35 ++++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 7 deletions(-) diff --git a/snapshot/elf/elf_image_reader.cc b/snapshot/elf/elf_image_reader.cc index bbf9b54e..8ee51d34 100644 --- a/snapshot/elf/elf_image_reader.cc +++ b/snapshot/elf/elf_image_reader.cc @@ -467,6 +467,20 @@ uint16_t ElfImageReader::FileType() const { return memory_.Is64Bit() ? header_64_.e_type : header_32_.e_type; } +bool ElfImageReader::SoName(std::string* name) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!InitializeDynamicArray()) { + return false; + } + + VMSize offset; + if (!dynamic_array_->GetValue(DT_SONAME, true, &offset)) { + return false; + } + + return ReadDynamicStringTableAtOffset(offset, name); +} + bool ElfImageReader::GetDynamicSymbol(const std::string& name, VMAddress* address, VMSize* size) { diff --git a/snapshot/elf/elf_image_reader.h b/snapshot/elf/elf_image_reader.h index 29f8b1eb..317b35ad 100644 --- a/snapshot/elf/elf_image_reader.h +++ b/snapshot/elf/elf_image_reader.h @@ -149,6 +149,13 @@ class ElfImageReader { //! The load bias is the actual load address minus the preferred load address. VMOffset GetLoadBias() const { return load_bias_; } + //! \brief Determines the name of this object using `DT_SONAME`, if present. + //! + //! \param[out] name The name of this object, only valid if this method + //! returns `true`. + //! \return `true` if a name was found for this object. + bool SoName(std::string* name); + //! \brief Reads information from the dynamic symbol table about the symbol //! identified by \a name. //! diff --git a/snapshot/linux/process_reader_linux.cc b/snapshot/linux/process_reader_linux.cc index 7a3e6092..811ddd03 100644 --- a/snapshot/linux/process_reader_linux.cc +++ b/snapshot/linux/process_reader_linux.cc @@ -433,7 +433,12 @@ void ProcessReaderLinux::InitializeModules() { } Module module = {}; - module.name = !entry.name.empty() ? entry.name : module_mapping->name; + std::string soname; + if (elf_reader->SoName(&soname) && !soname.empty()) { + module.name = soname; + } else { + module.name = !entry.name.empty() ? entry.name : module_mapping->name; + } module.elf_reader = elf_reader.get(); module.type = loader_base && elf_reader->Address() == loader_base ? ModuleSnapshot::kModuleTypeDynamicLoader diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index ea33f300..495adf7c 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -349,8 +349,13 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts( for (const auto& candidate : mappings_) { if (candidate.device == mapping.device && - candidate.inode == mapping.inode && - candidate.offset == 0) { + candidate.inode == mapping.inode +#if !defined(OS_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) + ) { possible_starts.push_back(&candidate); } if (mapping.Equals(candidate)) { diff --git a/util/linux/memory_map.h b/util/linux/memory_map.h index af194e99..28b8901f 100644 --- a/util/linux/memory_map.h +++ b/util/linux/memory_map.h @@ -76,14 +76,19 @@ class MemoryMap { //! it was obtained from. const Mapping* FindMappingWithName(const std::string& name) const; - //! \brief Find Mappings that share a Mapping's file, mapped from offset 0. + //! \brief Find possible initial mappings of files mapped over several + //! segments. //! //! Executables and libaries are typically loaded into several mappings with //! varying permissions for different segments. Portions of an ELF file may //! be mapped multiple times as part of loading the file, for example, when - //! initializing GNU_RELRO segments. This method searches for mappings at or - //! below \a mapping in memory that are mapped from the same file as \a - //! mapping from offset 0. + //! initializing GNU_RELRO segments. + //! + //! This method searches for mappings at or below \a mapping in memory that + //! are mapped from the same file as \a mapping from offset 0. + //! + //! On Android, ELF modules may be loaded from within a zipfile, so this + //! method may return mappings whose offset is not 0. //! //! This method is intended to help identify the possible base address for //! loaded modules, but it is the caller's responsibility to determine which diff --git a/util/linux/memory_map_test.cc b/util/linux/memory_map_test.cc index 645a0b4d..77d832b6 100644 --- a/util/linux/memory_map_test.cc +++ b/util/linux/memory_map_test.cc @@ -384,8 +384,12 @@ void ExpectFindFilePossibleMmapStarts(LinuxVMAddress mapping_start, EXPECT_EQ(mappings[0], mapping2); mappings = map.FindFilePossibleMmapStarts(*mapping3); +#if defined(OS_ANDROID) + EXPECT_EQ(mappings.size(), 2u); +#else ASSERT_EQ(mappings.size(), 1u); EXPECT_EQ(mappings[0], mapping1); +#endif } TEST(MemoryMap, FindFilePossibleMmapStarts) { @@ -430,6 +434,16 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) { std::vector<const MemoryMap::Mapping*> mappings; +#if defined(OS_ANDROID) + mappings = map.FindFilePossibleMmapStarts(*mapping1); + EXPECT_EQ(mappings.size(), 1u); + + mappings = map.FindFilePossibleMmapStarts(*mapping2); + EXPECT_EQ(mappings.size(), 2u); + + mappings = map.FindFilePossibleMmapStarts(*mapping3); + EXPECT_EQ(mappings.size(), 3u); +#else mappings = map.FindFilePossibleMmapStarts(*mapping1); ASSERT_EQ(mappings.size(), 1u); EXPECT_EQ(mappings[0], mapping1); @@ -441,6 +455,7 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) { mappings = map.FindFilePossibleMmapStarts(*mapping3); ASSERT_EQ(mappings.size(), 1u); EXPECT_EQ(mappings[0], mapping1); +#endif #if defined(ARCH_CPU_64_BITS) constexpr bool is_64_bit = true; @@ -562,27 +577,47 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) { auto mapping = map.FindMapping(file_mapping0.addr_as<VMAddress>()); ASSERT_TRUE(mapping); auto possible_starts = map.FindFilePossibleMmapStarts(*mapping); +#if defined(OS_ANDROID) + EXPECT_EQ(possible_starts.size(), 1u); +#else EXPECT_EQ(possible_starts.size(), 0u); +#endif mapping = map.FindMapping(file_mapping1.addr_as<VMAddress>()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); +#if defined(OS_ANDROID) + EXPECT_EQ(possible_starts.size(), 2u); +#else EXPECT_EQ(possible_starts.size(), 1u); +#endif mapping = map.FindMapping(file_mapping2.addr_as<VMAddress>()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); +#if defined(OS_ANDROID) + EXPECT_EQ(possible_starts.size(), 3u); +#else EXPECT_EQ(possible_starts.size(), 2u); +#endif mapping = map.FindMapping(file_mapping3.addr_as<VMAddress>()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); +#if defined(OS_ANDROID) + EXPECT_EQ(possible_starts.size(), 4u); +#else EXPECT_EQ(possible_starts.size(), 3u); +#endif mapping = map.FindMapping(file_mapping4.addr_as<VMAddress>()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); +#if defined(OS_ANDROID) + EXPECT_EQ(possible_starts.size(), 5u); +#else EXPECT_EQ(possible_starts.size(), 4u); +#endif } } // namespace From 7786acf0d7a2e274da5eb1200927d6edf6faec07 Mon Sep 17 00:00:00 2001 From: Hans Wennborg <hans@chromium.org> Date: Wed, 26 Sep 2018 17:54:38 +0200 Subject: [PATCH 025/401] win: move string_number_conversion_test asan/dll disabling into the win clause This fixes the upstreaming of https://chromium-review.googlesource.com/c/chromium/src/+/1113664 Bug: chromium:856174 Change-Id: I88cf6aeecef60e4eaf5c14dc9a66f0409255ccac Reviewed-on: https://chromium-review.googlesource.com/1245481 Commit-Queue: Hans Wennborg <hans@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/BUILD.gn | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index ec8d1daf..3ad253e0 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -641,11 +641,8 @@ source_set("util_test") { "win/scoped_process_suspend_test.cc", "win/session_end_watcher_test.cc", ] - } - - if (crashpad_is_in_chromium) { - if (is_asan && is_component_build) { + if (crashpad_is_in_chromium && is_asan && is_component_build) { # TODO(crbug.com/856174): Re-enable these once Windows ASan is fixed. sources -= [ "stdlib/string_number_conversion_test.cc" ] } From 0ad7e1fbbe297c1ebe16fca599bdda51e465c09f Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Fri, 28 Sep 2018 14:33:13 -0700 Subject: [PATCH 026/401] [fuchsia] disable MinidumpStringWriter.ConvertInvalidUTF8ToUTF16 re-enable once LUCI supports invalid UTF8 characters in test logs. Bug: fuchsia:DX-487 Bug: chromium:872892 Bug: chromium:889582 Tested: /system/test/crashpad_tests on Fuchsia device Change-Id: I3d6564423fb20554fdc39ffb7bd8e8bf7b1d3d48 Reviewed-on: https://chromium-review.googlesource.com/1251382 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- minidump/BUILD.gn | 4 ++++ minidump/minidump_string_writer_test.cc | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/minidump/BUILD.gn b/minidump/BUILD.gn index 88a10815..86966d82 100644 --- a/minidump/BUILD.gn +++ b/minidump/BUILD.gn @@ -154,6 +154,10 @@ source_set("minidump_test") { "minidump_writable_test.cc", ] + configs += [ + "../build:crashpad_is_in_fuchsia", + ] + deps = [ ":test_support", "../snapshot:test_support", diff --git a/minidump/minidump_string_writer_test.cc b/minidump/minidump_string_writer_test.cc index 382baaf7..1d654856 100644 --- a/minidump/minidump_string_writer_test.cc +++ b/minidump/minidump_string_writer_test.cc @@ -100,6 +100,12 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { } } +// Related tracking issues: +// https://fuchsia.atlassian.net/browse/DX-487 +// https://bugs.chromium.org/p/chromium/issues/detail?id=872892 +// https://bugs.chromium.org/p/chromium/issues/detail?id=889582 +// TODO: Re-enable test once LUCI supports invalid UTF8 characters in test logs. +#if !defined(CRASHPAD_IS_IN_FUCHSIA) TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { StringFile string_file; @@ -139,6 +145,7 @@ TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { EXPECT_NE(output_string.find(0xfffd), base::string16::npos); } } +#endif // !defined(CRASHPAD_IS_IN_FUCHSIA) TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { StringFile string_file; From 39d73623dd1ea016426b66a9645972753676c8c4 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 1 Oct 2018 10:08:43 -0700 Subject: [PATCH 027/401] Add jperaza to CONTRIBUTORS Change-Id: Ib4aa0cdb76517e70e07b1ca841c0166eecdab6b7 Reviewed-on: https://chromium-review.googlesource.com/1254944 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 2080cc45..8724b7f3 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -12,3 +12,4 @@ Mark Mentovai <mark@chromium.org> Robert Sesek <rsesek@chromium.org> Scott Graham <scottmg@chromium.org> +Joshua Peraza <jperaza@chromium.org> From 91781418bc4eb79e357687094811bab6430b10b2 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 2 Oct 2018 15:19:32 -0700 Subject: [PATCH 028/401] linux: Add CrashWithoutDump() When a renderer crashes in Multi-process WebView, the browser process may need to crash itself to maintain equivalent behavior with single process WebView. This allows it to do so without generating a dump of the browser process, which would provide no useful information. Change-Id: I272d6322269bd0ba8753b5b3959a613877eaf867 Reviewed-on: https://chromium-review.googlesource.com/c/1258082 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client.h | 6 ++++ client/crashpad_client_linux.cc | 50 +++++++++++++++------------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 154d9ace..ea0e7b6d 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -266,6 +266,12 @@ class CrashpadClient { //! CaptureContext() or similar. static void DumpWithoutCrash(NativeCPUContext* context); + //! \brief Disables any installed crash handler, including any + //! FirstChanceHandler and crashes the current process. + //! + //! \param[in] message A message to be logged before crashing. + static void CrashWithoutDump(const std::string& message); + //! \brief The type for custom handlers installed by clients. using FirstChanceHandler = bool (*)(int, siginfo_t*, ucontext_t*); diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 1e9d6518..e8e7f467 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -78,28 +78,8 @@ std::vector<std::string> BuildAppProcessArgs( #endif // OS_ANDROID -class SignalHandler { - public: - virtual void HandleCrashFatal(int signo, - siginfo_t* siginfo, - void* context) = 0; - virtual bool HandleCrashNonFatal(int signo, - siginfo_t* siginfo, - void* context) = 0; - - void SetFirstChanceHandler(CrashpadClient::FirstChanceHandler handler) { - first_chance_handler_ = handler; - } - - protected: - SignalHandler() = default; - ~SignalHandler() = default; - - CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr; -}; - // Launches a single use handler to snapshot this process. -class LaunchAtCrashHandler : public SignalHandler { +class LaunchAtCrashHandler { public: static LaunchAtCrashHandler* Get() { static LaunchAtCrashHandler* instance = new LaunchAtCrashHandler(); @@ -123,9 +103,7 @@ class LaunchAtCrashHandler : public SignalHandler { return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr); } - bool HandleCrashNonFatal(int signo, - siginfo_t* siginfo, - void* context) override { + bool HandleCrashNonFatal(int signo, siginfo_t* siginfo, void* context) { if (first_chance_handler_ && first_chance_handler_( signo, siginfo, static_cast<ucontext_t*>(context))) { @@ -162,13 +140,19 @@ class LaunchAtCrashHandler : public SignalHandler { return false; } - void HandleCrashFatal(int signo, siginfo_t* siginfo, void* context) override { - if (HandleCrashNonFatal(signo, siginfo, context)) { + void HandleCrashFatal(int signo, siginfo_t* siginfo, void* context) { + if (enabled_ && HandleCrashNonFatal(signo, siginfo, context)) { return; } Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr); } + void SetFirstChanceHandler(CrashpadClient::FirstChanceHandler handler) { + first_chance_handler_ = handler; + } + + static void Disable() { enabled_ = false; } + private: LaunchAtCrashHandler() = default; @@ -183,16 +167,20 @@ class LaunchAtCrashHandler : public SignalHandler { std::vector<const char*> argv_; std::vector<std::string> envp_strings_; std::vector<const char*> envp_; - bool set_envp_ = false; ExceptionInformation exception_information_; + CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr; + bool set_envp_ = false; + + static thread_local bool enabled_; DISALLOW_COPY_AND_ASSIGN(LaunchAtCrashHandler); }; +thread_local bool LaunchAtCrashHandler::enabled_ = true; // A pointer to the currently installed crash signal handler. This allows // the static method CrashpadClient::DumpWithoutCrashing to simulate a crash // using the currently configured crash handling strategy. -static SignalHandler* g_crash_handler; +static LaunchAtCrashHandler* g_crash_handler; } // namespace @@ -318,6 +306,12 @@ void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) { siginfo.si_signo, &siginfo, reinterpret_cast<void*>(context)); } +// static +void CrashpadClient::CrashWithoutDump(const std::string& message) { + LaunchAtCrashHandler::Disable(); + LOG(FATAL) << message; +} + // static void CrashpadClient::SetFirstChanceExceptionHandler( FirstChanceHandler handler) { From 21edfd3c3a20b1c57e5a46d472d4f219ed74ab8b Mon Sep 17 00:00:00 2001 From: Joshua Seaton <joshuaseaton@google.com> Date: Wed, 3 Oct 2018 14:44:57 -0700 Subject: [PATCH 029/401] [fuchsia] Move non-tests out of tests in the crashpad_tests package Test: /system/test/crashpad_tests successfully ran locally Change-Id: Iefefc1728444205efee5d22cbbd63a19869609df Reviewed-on: https://chromium-review.googlesource.com/c/1259447 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- BUILD.gn | 30 ++++++++++++++++++------------ test/test_paths.cc | 8 ++++---- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index 6da79cb6..ce9edf75 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -53,13 +53,21 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { { name = "crashpad_tests" }, + ] + + # Note that the infix of "crashpad_tests" below in + # binary/resource entries should be removed once + # crashpad_tests is moved out of the system image; + # until then, it is used to disambiguate the crashpad + # binaries and data from others within /system/(bin|data). + binaries = [ { name = "crashpad_test_test_multiprocess_exec_test_child" - dest = "crashpad_test_data/crashpad_test_test_multiprocess_exec_test_child" + dest = "crashpad_tests/crashpad_test_test_multiprocess_exec_test_child" }, { name = "http_transport_test_server" - dest = "crashpad_test_data/http_transport_test_server" + dest = "crashpad_tests/http_transport_test_server" }, ] @@ -81,15 +89,15 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { resources = [ { path = "util/net/testdata/ascii_http_body.txt" - dest = "crashpad_test_data/util/net/testdata/ascii_http_body.txt" + dest = "crashpad_tests/util/net/testdata/ascii_http_body.txt" }, { path = "util/net/testdata/binary_http_body.dat" - dest = "crashpad_test_data/util/net/testdata/binary_http_body.dat" + dest = "crashpad_tests/util/net/testdata/binary_http_body.dat" }, { path = "test/test_paths_test_data_root.txt" - dest = "crashpad_test_data/test/test_paths_test_data_root.txt" + dest = "crashpad_tests/test/test_paths_test_data_root.txt" }, ] @@ -97,16 +105,14 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { deps += [ "util:generate_test_server_key", ] - tests += [ - # These aren't actually tests, but that seems to be the only way to - # convince package() to get them from the output directory. + resources += [ { - name = "crashpad_util_test_cert.pem" - dest = "crashpad_test_data/crashpad_util_test_cert.pem" + path = "$root_out_dir/crashpad_util_test_cert.pem" + dest = "crashpad_tests/crashpad_util_test_cert.pem" }, { - name = "crashpad_util_test_key.pem" - dest = "crashpad_test_data/crashpad_util_test_key.pem" + path = "$root_out_dir/crashpad_util_test_key.pem" + dest = "crashpad_tests/crashpad_util_test_key.pem" }, ] } diff --git a/test/test_paths.cc b/test/test_paths.cc index 50165e43..b4b7a3cd 100644 --- a/test/test_paths.cc +++ b/test/test_paths.cc @@ -50,7 +50,7 @@ base::FilePath TestDataRootInternal() { // not appear as expected at /pkg/assets. Override the default so that tests // can find their data for now. // https://crashpad.chromium.org/bug/196. - asset_path = base::FilePath("/system/data/crashpad_test_data"); + asset_path = base::FilePath("/system/data/crashpad_tests"); #endif if (!IsTestDataRoot(asset_path)) { LOG(WARNING) << "Test data root seems invalid, continuing anyway"; @@ -133,7 +133,7 @@ base::FilePath TestPaths::Executable() { // not appear as expected at /pkg/bin. Override the default of /pkg/bin/app // so that tests can find the correct location for now. // https://crashpad.chromium.org/bug/196. - executable_path = base::FilePath("/system/test/crashpad_test_data/app"); + executable_path = base::FilePath("/system/bin/crashpad_tests/app"); #endif return executable_path; } @@ -208,7 +208,7 @@ base::FilePath TestPaths::BuildArtifact( // /pkg/bin/app so that tests can find the correct location for now. // https://crashpad.chromium.org/bug/196. directory = - base::FilePath(FILE_PATH_LITERAL("/system/test/crashpad_test_data")); + base::FilePath(FILE_PATH_LITERAL("/system/bin/crashpad_tests")); #else directory = base::FilePath(FILE_PATH_LITERAL("/pkg/bin")); #endif @@ -238,7 +238,7 @@ base::FilePath TestPaths::BuildArtifact( // things are actually run from a package. // https://crashpad.chromium.org/bug/196. directory = - base::FilePath(FILE_PATH_LITERAL("/system/test/crashpad_test_data")); + base::FilePath(FILE_PATH_LITERAL("/system/bin/crashpad_tests")); #endif extension = FILE_PATH_LITERAL(".pem"); break; From ce122b644ce2e50e2c55b8cf1af89308c7bf631d Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Thu, 4 Oct 2018 13:21:20 -0700 Subject: [PATCH 030/401] [util/net] add error message to scheme check * instead of just 'Check failed: scheme == "http"', we will have something like 'Check failed: scheme == "http". Got 'https' for scheme in 'https://for.bar'' * clangfmt on file Bug: fuchsia:DX-514 Change-Id: I043af7281d7f99ed5641c87920d806e340a38dea Tested=`out/Debug/crashpad_util_test` and Fuchsia logs Reviewed-on: https://chromium-review.googlesource.com/c/1262140 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- util/net/http_transport_socket.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/net/http_transport_socket.cc b/util/net/http_transport_socket.cc index 34d8deeb..75ed38fd 100644 --- a/util/net/http_transport_socket.cc +++ b/util/net/http_transport_socket.cc @@ -57,8 +57,7 @@ struct ScopedAddrinfoTraits { static addrinfo* InvalidValue() { return nullptr; } static void Free(addrinfo* ai) { freeaddrinfo(ai); } }; -using ScopedAddrinfo = - base::ScopedGeneric<addrinfo*, ScopedAddrinfoTraits>; +using ScopedAddrinfo = base::ScopedGeneric<addrinfo*, ScopedAddrinfoTraits>; class Stream { public: @@ -81,7 +80,7 @@ class FdStream : public Stream { return LoggingReadFileExactly(fd_, data, size); } - bool LoggingReadToEOF(std::string* result) override{ + bool LoggingReadToEOF(std::string* result) override { return crashpad::LoggingReadToEOF(fd_, result); } @@ -545,7 +544,8 @@ bool HTTPTransportSocket::ExecuteSynchronously(std::string* response_body) { } #if !defined(CRASHPAD_USE_BORINGSSL) - CHECK(scheme == "http"); + CHECK(scheme == "http") << "Got " << scheme << " for scheme in '" << url() + << "'"; #endif base::ScopedFD sock(CreateSocket(hostname, port)); From 83e37a9ac145414ba7a86217c208d6dc8edcb7ec Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Thu, 4 Oct 2018 14:40:48 -0700 Subject: [PATCH 031/401] [fuchsia] add commands for testing on Fuchsia TESTED=ran the commands! Change-Id: I7d8d3ca31a250005edcd3fb6269afffe8b3fbc89 Reviewed-on: https://chromium-review.googlesource.com/c/1263016 Reviewed-by: Scott Graham <scottmg@chromium.org> --- doc/developing.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/doc/developing.md b/doc/developing.md index 84d1cf76..4aaac6c1 100644 --- a/doc/developing.md +++ b/doc/developing.md @@ -193,6 +193,13 @@ $ cd ~/crashpad/crashpad $ python build/run_tests.py out/Debug ``` +To run a subset of the tests, use the --gtest\_filter flag, e.g., to run all the +tests for MinidumpStringWriter: + +```sh +$ python build/run_tests.py out/Debug --gtest_filter MinidumpStringWriter* +``` + ### Windows On Windows, `end_to_end_test.py` requires the CDB debugger, installed with @@ -220,6 +227,25 @@ variable. `run_tests.py` will upload test executables and data to a temporary location on the detected or selected device, run them, and clean up after itself when done. +### Fuchsia + +To test on Fuchsia, you need a connected device running Fuchsia and then run: + +```sh +$ gn gen out/fuchsia --args='target_os="fuchsia" target_cpu="x64" is_debug=true' +$ ninja -C out/fuchsia +$ python build/run_tests.py out/fuchsia +``` + +If you have multiple devices running, you will need to specify which device you +want using their hostname, for instance: + +```sh +$ export ZIRCON_NODENAME=scare-brook-skip-dried; \ + python build/run_tests.py out/fuchsia; \ + unset ZIRCON_NODENAME +``` + ## Contributing Crashpad’s contribution process is very similar to [Chromium’s contribution From 78d081ee4e91244d4aa5e158eff848bc225afa1a Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 4 Oct 2018 17:25:57 -0700 Subject: [PATCH 032/401] linux: save and restore old signal actions Change-Id: I9a69bf347ef70f6a20aaff9cdd4281edb5afff3d Reviewed-on: https://chromium-review.googlesource.com/c/1263026 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client_linux.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index e8e7f467..77faa0aa 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -100,7 +100,7 @@ class LaunchAtCrashHandler { &exception_information_)); StringVectorToCStringVector(argv_strings_, &argv_); - return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr); + return Signals::InstallCrashHandlers(HandleCrash, 0, &old_actions_); } bool HandleCrashNonFatal(int signo, siginfo_t* siginfo, void* context) { @@ -144,7 +144,8 @@ class LaunchAtCrashHandler { if (enabled_ && HandleCrashNonFatal(signo, siginfo, context)) { return; } - Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr); + Signals::RestoreHandlerAndReraiseSignalOnReturn( + siginfo, old_actions_.ActionForSignal(signo)); } void SetFirstChanceHandler(CrashpadClient::FirstChanceHandler handler) { @@ -163,6 +164,7 @@ class LaunchAtCrashHandler { state->HandleCrashFatal(signo, siginfo, context); } + Signals::OldActions old_actions_ = {}; std::vector<std::string> argv_strings_; std::vector<const char*> argv_; std::vector<std::string> envp_strings_; From 1b4fdd0fd079ff650e37b9aa30b88093e59097ac Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 5 Oct 2018 10:52:41 -0700 Subject: [PATCH 033/401] fuchsia: Re-enable HTTPS transport, but disable tests The HTTPS tests are flaky on Fuchsia bots, so TLS transport was disabled. However, a different CHECK fails in prod when a crash is attempted to be uploaded via an 'https' url. So for now, re-enable the https transport, but disable the https tests that were flaky, so they can be debugged separately. Additionally, there was a small error in https://chromium.googlesource.com/crashpad/crashpad/+/21edfd3c3a20b1c57e5a46d472d4f219ed74ab8b that wasn't caught because these tests were disabled; fix the path to test server certs on Fuchsia. Bug: fuchsia:DX-382 Change-Id: I4ad0649ecb6d0644b1dfcf08bbb097d3a0cd40d0 Reviewed-on: https://chromium-review.googlesource.com/c/1265197 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Francois Rousseau <frousseau@google.com> --- test/test_paths.cc | 2 +- util/net/http_transport_test.cc | 3 ++- util/net/tls.gni | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test/test_paths.cc b/test/test_paths.cc index b4b7a3cd..3b611b12 100644 --- a/test/test_paths.cc +++ b/test/test_paths.cc @@ -238,7 +238,7 @@ base::FilePath TestPaths::BuildArtifact( // things are actually run from a package. // https://crashpad.chromium.org/bug/196. directory = - base::FilePath(FILE_PATH_LITERAL("/system/bin/crashpad_tests")); + base::FilePath(FILE_PATH_LITERAL("/system/data/crashpad_tests")); #endif extension = FILE_PATH_LITERAL(".pem"); break; diff --git a/util/net/http_transport_test.cc b/util/net/http_transport_test.cc index d73dc992..19422ec9 100644 --- a/util/net/http_transport_test.cc +++ b/util/net/http_transport_test.cc @@ -364,7 +364,8 @@ TEST_P(HTTPTransport, Upload33k_LengthUnknown) { RunUpload33k(GetParam(), false); } -#if defined(CRASHPAD_USE_BORINGSSL) +// This should be on for Fuchsia, but DX-382. Debug and re-enabled. +#if defined(CRASHPAD_USE_BORINGSSL) && !defined(OS_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/tls.gni b/util/net/tls.gni index 68c7eb7d..ed9aa861 100644 --- a/util/net/tls.gni +++ b/util/net/tls.gni @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("../../build/crashpad_buildconfig.gni") + declare_args() { - # This should at least be on for Fuchsia, but DX-382 happened. - # TODO(mark): Figure out what went wrong and re-enable. - crashpad_use_boringssl_for_http_transport_socket = false + crashpad_use_boringssl_for_http_transport_socket = crashpad_is_fuchsia } From 9554a89ab60abf79eb62337c8519def764c5b9dc Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 4 Oct 2018 15:48:54 -0700 Subject: [PATCH 034/401] fuchsia: Use zx_task_resume_from_exception() instead of zx_task_resume() zx_task_resume() is deprecated for exception resumption, and replaced by zx_task_resume_from_exception(). The latter requires an additional argument, so plumb the exception port on which the exception was delivered through to where it needs to be resumed. Bug: fuchsia:ZX-2720 Change-Id: If3984ce13eb1735d061faaac9eecd42e0251d25f Reviewed-on: https://chromium-review.googlesource.com/c/1263017 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Francois Rousseau <frousseau@google.com> --- .../fuchsia/crash_report_exception_handler.cc | 33 +++++++++++-------- .../fuchsia/crash_report_exception_handler.h | 20 +++++++---- handler/fuchsia/exception_handler_server.cc | 5 +-- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index 3305fef6..214cbadc 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -30,20 +30,24 @@ namespace { class ScopedThreadResumeAfterException { public: - ScopedThreadResumeAfterException(const zx::thread& thread) - : thread_(thread) {} + ScopedThreadResumeAfterException(const zx::thread& thread, + const zx::unowned_port& exception_port) + : thread_(thread), exception_port_(exception_port) {} ~ScopedThreadResumeAfterException() { DCHECK(thread_->is_valid()); // Resuming with ZX_RESUME_TRY_NEXT chains to the next handler. In normal // operation, there won't be another beyond this one, which will result in // the kernel terminating the process. zx_status_t status = - thread_->resume(ZX_RESUME_EXCEPTION | ZX_RESUME_TRY_NEXT); - ZX_LOG_IF(ERROR, status != ZX_OK, status) << "zx_task_resume"; + thread_->resume_from_exception(*exception_port_, ZX_RESUME_TRY_NEXT); + ZX_LOG_IF(ERROR, status != ZX_OK, status) + << "zx_task_resume_from_exception"; } private: zx::unowned_thread thread_; + const zx::unowned_port& exception_port_; + DISALLOW_COPY_AND_ASSIGN(ScopedThreadResumeAfterException); }; @@ -63,15 +67,17 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportExceptionHandler::~CrashReportExceptionHandler() {} -bool CrashReportExceptionHandler::HandleException(uint64_t process_id, - uint64_t thread_id) { +bool CrashReportExceptionHandler::HandleException( + uint64_t process_id, + uint64_t thread_id, + const zx::unowned_port& exception_port) { // TODO(scottmg): This function needs to be instrumented with metrics calls, // https://crashpad.chromium.org/bug/230. zx::process process(GetProcessFromKoid(process_id)); if (!process.is_valid()) { - // There's no way to zx_task_resume() the thread if the process retrieval - // fails. Assume that the process has been already killed, and bail. + // There's no way to resume the thread if the process retrieval fails. + // Assume that the process has been already killed, and bail. return false; } @@ -80,16 +86,17 @@ bool CrashReportExceptionHandler::HandleException(uint64_t process_id, return false; } - return HandleExceptionHandles(process, thread); + return HandleExceptionHandles(process, thread, exception_port); } bool CrashReportExceptionHandler::HandleExceptionHandles( const zx::process& process, - const zx::thread& thread) { + const zx::thread& thread, + const zx::unowned_port& exception_port) { // Now that the thread has been successfully retrieved, it is possible to - // correctly call zx_task_resume() to continue exception processing, even if - // something else during this function fails. - ScopedThreadResumeAfterException resume(thread); + // correctly call zx_task_resume_from_exception() to continue exception + // processing, even if something else during this function fails. + ScopedThreadResumeAfterException resume(thread, exception_port); ProcessSnapshotFuchsia process_snapshot; if (!process_snapshot.Initialize(process)) { diff --git a/handler/fuchsia/crash_report_exception_handler.h b/handler/fuchsia/crash_report_exception_handler.h index 8eacc11f..a84eb384 100644 --- a/handler/fuchsia/crash_report_exception_handler.h +++ b/handler/fuchsia/crash_report_exception_handler.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_HANDLER_FUCHSIA_CRASH_REPORT_EXCEPTION_HANDLER_H_ #define CRASHPAD_HANDLER_FUCHSIA_CRASH_REPORT_EXCEPTION_HANDLER_H_ +#include <lib/zx/port.h> #include <lib/zx/process.h> #include <lib/zx/thread.h> #include <stdint.h> @@ -70,28 +71,35 @@ class CrashReportExceptionHandler { //! \brief Called when the exception handler server has caught an exception //! and wants a crash dump to be taken. //! - //! This function is expected to call `zx_task_resume()` in order to complete - //! handling of the exception. + //! This function is expected to call `zx_task_resume_from_exception()` in + //! order to complete handling of the exception. //! //! \param[in] process_id The koid of the process which sustained the //! exception. //! \param[in] thread_id The koid of the thread which sustained the exception. + //! \param[in] exception_port The exception port on which the exception was + //! serviced. This can be used to resume the excepting thread. //! \return `true` on success, or `false` with an error logged. - bool HandleException(uint64_t process_id, uint64_t thread_id); + bool HandleException(uint64_t process_id, + uint64_t thread_id, + const zx::unowned_port& exception_port); //! \brief Called when the exception handler server has caught an exception //! and wants a crash dump to be taken. //! - //! This function is expected to call `zx_task_resume()` in order to complete - //! handling of the exception. + //! This function is expected to call `zx_task_resume_from_exception()` in + //! order to complete handling of the exception. //! //! \param[in] process The handle to the process which sustained the //! exception. //! \param[in] thread The handle to the thread of \a process which sustained //! the exception. + //! \param[in] exception_port The exception port on which the exception was + //! serviced. This can be used to resume the excepting thread. //! \return `true` on success, or `false` with an error logged. bool HandleExceptionHandles(const zx::process& process, - const zx::thread& thread); + const zx::thread& thread, + const zx::unowned_port& exception_port); private: CrashReportDatabase* database_; // weak diff --git a/handler/fuchsia/exception_handler_server.cc b/handler/fuchsia/exception_handler_server.cc index 1b2c829f..8c5b1434 100644 --- a/handler/fuchsia/exception_handler_server.cc +++ b/handler/fuchsia/exception_handler_server.cc @@ -47,8 +47,9 @@ void ExceptionHandlerServer::Run(CrashReportExceptionHandler* handler) { continue; } - bool result = - handler->HandleException(packet.exception.pid, packet.exception.tid); + bool result = handler->HandleException(packet.exception.pid, + packet.exception.tid, + zx::unowned_port(exception_port_)); if (!result) { LOG(ERROR) << "HandleException failed"; } From 9b2a119dc6d8e334de92e4500e88085ce1ed7491 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 8 Oct 2018 17:43:20 -0700 Subject: [PATCH 035/401] elf: don't warn on trailing unread bytes in the elf dynamic array This warning triggers reliably on most binaries and on android, spams the logcat which may obfuscate other errors. The actual amount varies, but is typically 40 bytes for 32-bit android system libraries, 80 bytes for 64-bit android system libraries, 64 bytes for linux system libraries (on my machine), but so far they're all zeroes. Change-Id: I658434e8290c75641a3b17034ebdd958834bcd69 Reviewed-on: https://chromium-review.googlesource.com/c/1269740 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- snapshot/elf/elf_dynamic_array_reader.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/snapshot/elf/elf_dynamic_array_reader.cc b/snapshot/elf/elf_dynamic_array_reader.cc index 9a44e12e..a39712ac 100644 --- a/snapshot/elf/elf_dynamic_array_reader.cc +++ b/snapshot/elf/elf_dynamic_array_reader.cc @@ -42,9 +42,6 @@ bool Read(const ProcessMemoryRange& memory, switch (entry.d_tag) { case DT_NULL: values->swap(local_values); - if (size != 0) { - LOG(WARNING) << size << " trailing bytes not read"; - } return true; case DT_NEEDED: // Skip these entries for now. From 0fb6541428733054f44fb3b3cd085c08ef48aae1 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Wed, 10 Oct 2018 10:26:26 -0700 Subject: [PATCH 036/401] [fuchsia][linux] optionally return local report ID on exception handling this allows us to upload that specific local report downstream Bug: fuchsia:DX-543 Change-Id: Ide262575078aaf641f2e9321cd7796e9d1780f12 Tested: CQ Reviewed-on: https://chromium-review.googlesource.com/c/1271998 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- .../fuchsia/crash_report_exception_handler.cc | 12 +++++++++--- .../fuchsia/crash_report_exception_handler.h | 11 +++++++++-- .../linux/crash_report_exception_handler.cc | 19 ++++++++++++------- .../linux/crash_report_exception_handler.h | 10 +++++++--- handler/linux/exception_handler_server.h | 11 +++++++++-- .../linux/exception_handler_server_test.cc | 7 +++++-- 6 files changed, 51 insertions(+), 19 deletions(-) diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index 214cbadc..bd76a88d 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -70,7 +70,8 @@ CrashReportExceptionHandler::~CrashReportExceptionHandler() {} bool CrashReportExceptionHandler::HandleException( uint64_t process_id, uint64_t thread_id, - const zx::unowned_port& exception_port) { + const zx::unowned_port& exception_port, + UUID* local_report_id) { // TODO(scottmg): This function needs to be instrumented with metrics calls, // https://crashpad.chromium.org/bug/230. @@ -86,13 +87,15 @@ bool CrashReportExceptionHandler::HandleException( return false; } - return HandleExceptionHandles(process, thread, exception_port); + return HandleExceptionHandles( + process, thread, exception_port, local_report_id); } bool CrashReportExceptionHandler::HandleExceptionHandles( const zx::process& process, const zx::thread& thread, - const zx::unowned_port& exception_port) { + const zx::unowned_port& exception_port, + UUID* local_report_id) { // Now that the thread has been successfully retrieved, it is possible to // correctly call zx_task_resume_from_exception() to continue exception // processing, even if something else during this function fails. @@ -178,6 +181,9 @@ bool CrashReportExceptionHandler::HandleExceptionHandles( if (database_status != CrashReportDatabase::kNoError) { return false; } + if (local_report_id != nullptr) { + *local_report_id = uuid; + } if (upload_thread_) { upload_thread_->ReportPending(uuid); diff --git a/handler/fuchsia/crash_report_exception_handler.h b/handler/fuchsia/crash_report_exception_handler.h index a84eb384..88b4cca2 100644 --- a/handler/fuchsia/crash_report_exception_handler.h +++ b/handler/fuchsia/crash_report_exception_handler.h @@ -29,6 +29,7 @@ #include "client/crash_report_database.h" #include "handler/crash_report_upload_thread.h" #include "handler/user_stream_data_source.h" +#include "util/misc/uuid.h" namespace crashpad { @@ -79,10 +80,13 @@ class CrashReportExceptionHandler { //! \param[in] thread_id The koid of the thread which sustained the exception. //! \param[in] exception_port The exception port on which the exception was //! serviced. This can be used to resume the excepting thread. + //! \param[out] local_report_id The unique identifier for the report created + //! in the local report database. Optional. //! \return `true` on success, or `false` with an error logged. bool HandleException(uint64_t process_id, uint64_t thread_id, - const zx::unowned_port& exception_port); + const zx::unowned_port& exception_port, + UUID* local_report_id = nullptr); //! \brief Called when the exception handler server has caught an exception //! and wants a crash dump to be taken. @@ -96,10 +100,13 @@ class CrashReportExceptionHandler { //! the exception. //! \param[in] exception_port The exception port on which the exception was //! serviced. This can be used to resume the excepting thread. + //! \param[out] local_report_id The unique identifier for the report created + //! in the local report database. Optional. //! \return `true` on success, or `false` with an error logged. bool HandleExceptionHandles(const zx::process& process, const zx::thread& thread, - const zx::unowned_port& exception_port); + const zx::unowned_port& exception_port, + UUID* local_report_id = nullptr); private: CrashReportDatabase* database_; // weak diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 101c49f5..71a7009b 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -43,9 +43,9 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportExceptionHandler::~CrashReportExceptionHandler() = default; -bool CrashReportExceptionHandler::HandleException( - pid_t client_process_id, - const ClientInformation& info) { +bool CrashReportExceptionHandler::HandleException(pid_t client_process_id, + const ClientInformation& info, + UUID* local_report_id) { Metrics::ExceptionEncountered(); DirectPtraceConnection connection; @@ -55,13 +55,14 @@ bool CrashReportExceptionHandler::HandleException( return false; } - return HandleExceptionWithConnection(&connection, info); + return HandleExceptionWithConnection(&connection, info, local_report_id); } bool CrashReportExceptionHandler::HandleExceptionWithBroker( pid_t client_process_id, const ClientInformation& info, - int broker_sock) { + int broker_sock, + UUID* local_report_id) { Metrics::ExceptionEncountered(); PtraceClient client; @@ -71,12 +72,13 @@ bool CrashReportExceptionHandler::HandleExceptionWithBroker( return false; } - return HandleExceptionWithConnection(&client, info); + return HandleExceptionWithConnection(&client, info, local_report_id); } bool CrashReportExceptionHandler::HandleExceptionWithConnection( PtraceConnection* connection, - const ClientInformation& info) { + const ClientInformation& info, + UUID* local_report_id) { ProcessSnapshotLinux process_snapshot; if (!process_snapshot.Initialize(connection)) { Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed); @@ -180,6 +182,9 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( Metrics::CaptureResult::kFinishedWritingCrashReportFailed); return false; } + if (local_report_id != nullptr) { + *local_report_id = uuid; + } if (upload_thread_) { upload_thread_->ReportPending(uuid); diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index 24d5995a..9951d840 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -26,6 +26,7 @@ #include "util/linux/exception_handler_protocol.h" #include "util/linux/ptrace_connection.h" #include "util/misc/address_types.h" +#include "util/misc/uuid.h" namespace crashpad { @@ -64,15 +65,18 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { // ExceptionHandlerServer::Delegate: bool HandleException(pid_t client_process_id, - const ClientInformation& info) override; + const ClientInformation& info, + UUID* local_report_id = nullptr) override; bool HandleExceptionWithBroker(pid_t client_process_id, const ClientInformation& info, - int broker_sock) override; + int broker_sock, + UUID* local_report_id = nullptr) override; private: bool HandleExceptionWithConnection(PtraceConnection* connection, - const ClientInformation& info); + const ClientInformation& info, + UUID* local_report_id = nullptr); CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index 5f491826..239aeea7 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -26,6 +26,7 @@ #include "util/linux/exception_handler_protocol.h" #include "util/misc/address_types.h" #include "util/misc/initialization_state_dcheck.h" +#include "util/misc/uuid.h" namespace crashpad { @@ -72,9 +73,12 @@ class ExceptionHandlerServer { //! //! \param[in] client_process_id The process ID of the crashing client. //! \param[in] info Information on the client. + //! \param[out] local_report_id The unique identifier for the report created + //! in the local report database. Optional. //! \return `true` on success. `false` on failure with a message logged. virtual bool HandleException(pid_t client_process_id, - const ClientInformation& info) = 0; + const ClientInformation& info, + UUID* local_report_id = nullptr) = 0; //! \brief Called on the receipt of a crash dump request from a client for a //! crash that should be mediated by a PtraceBroker. @@ -82,10 +86,13 @@ class ExceptionHandlerServer { //! \param[in] client_process_id The process ID of the crashing client. //! \param[in] info Information on the client. //! \param[in] broker_sock A socket connected to the PtraceBroker. + //! \param[out] local_report_id The unique identifier for the report created + //! in the local report database. Optional. //! \return `true` on success. `false` on failure with a message logged. virtual bool HandleExceptionWithBroker(pid_t client_process_id, const ClientInformation& info, - int broker_sock) = 0; + int broker_sock, + UUID* local_report_id = nullptr) = 0; protected: ~Delegate() {} diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index eda14d31..083a4ea5 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -25,6 +25,7 @@ #include "util/linux/exception_handler_client.h" #include "util/linux/ptrace_client.h" #include "util/linux/scoped_pr_set_ptracer.h" +#include "util/misc/uuid.h" #include "util/synchronization/semaphore.h" #include "util/thread/thread.h" @@ -101,7 +102,8 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { } bool HandleException(pid_t client_process_id, - const ClientInformation& info) override { + const ClientInformation& info, + UUID* local_report_id = nullptr) override { DirectPtraceConnection connection; bool connected = connection.Initialize(client_process_id); EXPECT_TRUE(connected); @@ -114,7 +116,8 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { bool HandleExceptionWithBroker(pid_t client_process_id, const ClientInformation& info, - int broker_sock) override { + int broker_sock, + UUID* local_report_id = nullptr) override { PtraceClient client; bool connected = client.Initialize(broker_sock, client_process_id); EXPECT_TRUE(connected); From 1c09361c2cde6030a251d2b10553c14d747a8c35 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 11 Oct 2018 14:51:52 -0700 Subject: [PATCH 037/401] fuchsia: Let util build in Mac-host builds Some of the minidump functionality is going to be used in Fuchsia in host side tools (in zxdb, the debugger). This fixes the Mac-host build of util. Change-Id: Ifeb3bd9c7fa29c99a272c97c2813b9c201ddfe88 Reviewed-on: https://chromium-review.googlesource.com/c/1277774 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- util/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index 3ad253e0..fb053e06 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -20,7 +20,7 @@ if (crashpad_is_in_chromium) { } if (crashpad_is_mac) { - if (crashpad_is_in_chromium) { + if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { import("//build/config/sysroot.gni") } else { import("//third_party/mini_chromium/mini_chromium/build/sysroot.gni") From 237c5ebdf3a911cd09c2843822fe3d7c5081ed54 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 11 Oct 2018 15:56:22 -0700 Subject: [PATCH 038/401] fuchsia: Fix include_dirs for host Mac build Change-Id: I157fe2ab95d0b152ef5cc09cd0b6e56649c9f727 Reviewed-on: https://chromium-review.googlesource.com/c/1277777 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- util/BUILD.gn | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index fb053e06..0f099885 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -416,7 +416,11 @@ static_library("util") { public_configs = [ "..:crashpad_config" ] # Include generated files starting with "util". - include_dirs = [ "$root_gen_dir/third_party/crashpad/crashpad" ] + if (crashpad_is_in_fuchsia) { + include_dirs = [ "$root_gen_dir/third_party/crashpad" ] + } else { + include_dirs = [ "$root_gen_dir/third_party/crashpad/crashpad" ] + } public_deps = [ "../compat", From 7682f0f6ebbd5ea90f29c8b5c3cad076eb9f3fb3 Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Fri, 12 Oct 2018 13:12:01 -0700 Subject: [PATCH 039/401] Add ThreadSnapshotMinidump Only partially implemented, but ProcessSnapshotMinidump now returns them appropriately. Bug: crashpad:10 Change-Id: I44f598256965e404f62bd93e9e2efc61527298db Reviewed-on: https://chromium-review.googlesource.com/c/1278280 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/BUILD.gn | 2 + .../minidump/process_snapshot_minidump.cc | 51 +++++++++++- snapshot/minidump/process_snapshot_minidump.h | 6 ++ .../process_snapshot_minidump_test.cc | 54 ++++++++++++ snapshot/minidump/thread_snapshot_minidump.cc | 83 +++++++++++++++++++ snapshot/minidump/thread_snapshot_minidump.h | 61 ++++++++++++++ snapshot/snapshot.gyp | 2 + 7 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 snapshot/minidump/thread_snapshot_minidump.cc create mode 100644 snapshot/minidump/thread_snapshot_minidump.h diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 134df8b1..85a2a500 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -48,6 +48,8 @@ static_library("snapshot") { "minidump/module_snapshot_minidump.h", "minidump/process_snapshot_minidump.cc", "minidump/process_snapshot_minidump.h", + "minidump/thread_snapshot_minidump.cc", + "minidump/thread_snapshot_minidump.h", "module_snapshot.h", "process_snapshot.h", "snapshot_constants.h", diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 652e0e4c..97db3bdb 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -86,7 +86,8 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { if (!InitializeCrashpadInfo() || !InitializeMiscInfo() || - !InitializeModules()) { + !InitializeModules() || + !InitializeThreads()) { return false; } @@ -159,8 +160,11 @@ const SystemSnapshot* ProcessSnapshotMinidump::System() const { std::vector<const ThreadSnapshot*> ProcessSnapshotMinidump::Threads() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return std::vector<const ThreadSnapshot*>(); + std::vector<const ThreadSnapshot*> threads; + for (const auto& thread : threads_) { + threads.push_back(thread.get()); + } + return threads; } std::vector<const ModuleSnapshot*> ProcessSnapshotMinidump::Modules() const { @@ -390,4 +394,45 @@ bool ProcessSnapshotMinidump::InitializeModulesCrashpadInfo( return true; } +bool ProcessSnapshotMinidump::InitializeThreads() { + const auto& stream_it = stream_map_.find(kMinidumpStreamTypeThreadList); + if (stream_it == stream_map_.end()) { + return true; + } + + if (stream_it->second->DataSize < sizeof(MINIDUMP_THREAD_LIST)) { + LOG(ERROR) << "thread_list size mismatch"; + return false; + } + + if (!file_reader_->SeekSet(stream_it->second->Rva)) { + return false; + } + + uint32_t thread_count; + if (!file_reader_->ReadExactly(&thread_count, sizeof(thread_count))) { + return false; + } + + if (sizeof(MINIDUMP_THREAD_LIST) + thread_count * sizeof(MINIDUMP_THREAD) != + stream_it->second->DataSize) { + LOG(ERROR) << "thread_list size mismatch"; + 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<internal::ThreadSnapshotMinidump>(); + if (!thread->Initialize(file_reader_, thread_rva)) { + return false; + } + + threads_.push_back(std::move(thread)); + } + + return true; +} + } // namespace crashpad diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 9ba5d9c6..d15ea2fb 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -30,6 +30,7 @@ #include "snapshot/exception_snapshot.h" #include "snapshot/memory_snapshot.h" #include "snapshot/minidump/module_snapshot_minidump.h" +#include "snapshot/minidump/thread_snapshot_minidump.h" #include "snapshot/module_snapshot.h" #include "snapshot/process_snapshot.h" #include "snapshot/system_snapshot.h" @@ -85,6 +86,10 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { // Initialize(). bool InitializeModules(); + // Initializes data carried in a MINIDUMP_THREAD_LIST stream on behalf of + // Initialize(). + bool InitializeThreads(); + // Initializes data carried in a MinidumpModuleCrashpadInfoList structure on // behalf of InitializeModules(). This makes use of MinidumpCrashpadInfo as // well, so it must be called after InitializeCrashpadInfo(). @@ -100,6 +105,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector<MINIDUMP_DIRECTORY> stream_directory_; std::map<MinidumpStreamType, const MINIDUMP_LOCATION_DESCRIPTOR*> stream_map_; std::vector<std::unique_ptr<internal::ModuleSnapshotMinidump>> modules_; + std::vector<std::unique_ptr<internal::ThreadSnapshotMinidump>> threads_; std::vector<UnloadedModuleSnapshot> unloaded_modules_; MinidumpCrashpadInfo crashpad_info_; std::map<std::string, std::string> annotations_simple_map_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index ed179394..a08fbe47 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -452,6 +452,60 @@ TEST(ProcessSnapshotMinidump, ProcessID) { EXPECT_EQ(process_snapshot.ProcessID(), kTestProcessId); } +TEST(ProcessSnapshotMinidump, Threads) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + MINIDUMP_THREAD minidump_thread = {}; + uint32_t minidump_thread_count = 4; + + minidump_thread.ThreadId = 42; + minidump_thread.Teb = 24; + + MINIDUMP_DIRECTORY minidump_thread_list_directory = {}; + minidump_thread_list_directory.StreamType = kMinidumpStreamTypeThreadList; + minidump_thread_list_directory.Location.DataSize = + sizeof(MINIDUMP_THREAD_LIST) + + minidump_thread_count * sizeof(MINIDUMP_THREAD); + minidump_thread_list_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + // Fields in MINIDUMP_THREAD_LIST. + EXPECT_TRUE( + string_file.Write(&minidump_thread_count, sizeof(minidump_thread_count))); + for (uint32_t minidump_thread_index = 0; + minidump_thread_index < minidump_thread_count; + ++minidump_thread_index) { + EXPECT_TRUE(string_file.Write(&minidump_thread, sizeof(minidump_thread))); + minidump_thread.ThreadId++; + } + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + EXPECT_TRUE(string_file.Write(&minidump_thread_list_directory, + sizeof(minidump_thread_list_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + 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<const ThreadSnapshot*> threads = process_snapshot.Threads(); + ASSERT_EQ(threads.size(), minidump_thread_count); + + uint32_t thread_id = 42; + for (const auto& thread : threads) { + EXPECT_EQ(thread->ThreadID(), thread_id); + EXPECT_EQ(thread->ThreadSpecificDataAddress(), 24UL); + thread_id++; + } +} + } // namespace } // namespace test } // namespace crashpad diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc new file mode 100644 index 00000000..9bf2b718 --- /dev/null +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -0,0 +1,83 @@ +// Copyright 2018 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/minidump/thread_snapshot_minidump.h" + +namespace crashpad { +namespace internal { + +ThreadSnapshotMinidump::ThreadSnapshotMinidump() + : ThreadSnapshot(), + minidump_thread_(), + initialized_() { +} + +ThreadSnapshotMinidump::~ThreadSnapshotMinidump() { +} + +bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, + RVA minidump_thread_rva) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + if (!file_reader->SeekSet(minidump_thread_rva)) { + return false; + } + + if (!file_reader->ReadExactly(&minidump_thread_, sizeof(minidump_thread_))) { + return false; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +uint64_t ThreadSnapshotMinidump::ThreadID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_thread_.ThreadId; +} + +int ThreadSnapshotMinidump::SuspendCount() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_thread_.SuspendCount; +} + +uint64_t ThreadSnapshotMinidump::ThreadSpecificDataAddress() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_thread_.Teb; +} + +int ThreadSnapshotMinidump::Priority() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_thread_.Priority; +} + +const CPUContext* ThreadSnapshotMinidump::Context() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return nullptr; +} + +const MemorySnapshot* ThreadSnapshotMinidump::Stack() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return nullptr; +} + +std::vector<const MemorySnapshot*> ThreadSnapshotMinidump::ExtraMemory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return std::vector<const MemorySnapshot*>(); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/minidump/thread_snapshot_minidump.h b/snapshot/minidump/thread_snapshot_minidump.h new file mode 100644 index 00000000..18a17b28 --- /dev/null +++ b/snapshot/minidump/thread_snapshot_minidump.h @@ -0,0 +1,61 @@ +// Copyright 2018 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_MINIDUMP_THREAD_SNAPSHOT_MINIDUMP_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_THREAD_SNAPSHOT_MINIDUMP_H_ + +#include <windows.h> + +#include "minidump/minidump_extensions.h" +#include "snapshot/thread_snapshot.h" +#include "util/file/file_reader.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { + +//! \brief A ThreadSnapshot based on a thread in a minidump file. +class ThreadSnapshotMinidump : public ThreadSnapshot { + public: + ThreadSnapshotMinidump(); + ~ThreadSnapshotMinidump() override; + + //! \brief Initializes the object. + //! + //! \param[in] file_reader A file reader corresponding to a minidump file. + //! The file reader must support seeking. + //! \param[in] minidump_thread_rva The file offset in \a file_reader at which + //! the thread’s MINIDUMP_THREAD structure is located. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! an appropriate message logged. + bool Initialize(FileReaderInterface* file_reader, RVA minidump_thread_rva); + + const CPUContext* Context() const override; + const MemorySnapshot* Stack() const override; + uint64_t ThreadID() const override; + int SuspendCount() const override; + int Priority() const override; + uint64_t ThreadSpecificDataAddress() const override; + std::vector<const MemorySnapshot*> ExtraMemory() const override; + + private: + MINIDUMP_THREAD minidump_thread_; + InitializationStateDcheck initialized_; +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_THREAD_SNAPSHOT_MINIDUMP_H_ diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index a78d21f9..7fb4ba82 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -119,6 +119,8 @@ 'minidump/module_snapshot_minidump.h', 'minidump/process_snapshot_minidump.cc', 'minidump/process_snapshot_minidump.h', + 'minidump/thread_snapshot_minidump.cc', + 'minidump/thread_snapshot_minidump.h', 'module_snapshot.h', 'posix/timezone.cc', 'posix/timezone.h', From 46b329b3690d995d953963a24cae92b9fb9a935c Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 16 Oct 2018 10:49:43 -0700 Subject: [PATCH 040/401] list headers' includes as public dependencies if only declared as deps, not public_deps, then any header file depending on these headers need to also list these dependencies Change-Id: I1d5f6a70d0fb80bf9d7368884247ceee036d1b14 Tested: CQ Reviewed-on: https://chromium-review.googlesource.com/c/1282013 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- client/BUILD.gn | 5 ++--- handler/BUILD.gn | 10 ++++++---- handler/minidump_to_upload_parameters.cc | 1 + handler/minidump_to_upload_parameters.h | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/client/BUILD.gn b/client/BUILD.gn index a82a8dd4..f23185de 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -77,8 +77,7 @@ static_library("client") { public_configs = [ "..:crashpad_config" ] - deps = [ - "../compat", + public_deps = [ "../third_party/mini_chromium:base", "../util", ] @@ -89,7 +88,7 @@ static_library("client") { } if (crashpad_is_fuchsia) { - deps += [ "../third_party/fuchsia:zx" ] + deps = [ "../third_party/fuchsia:zx" ] if (crashpad_is_in_fuchsia) { deps += [ "//zircon/public/lib/fdio" ] } diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 93fd540a..a1fe65da 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -67,14 +67,16 @@ static_library("handler") { public_configs = [ "..:crashpad_config" ] - deps = [ + public_deps = [ "../client", - "../compat", + "../third_party/mini_chromium:base", + "../util", + ] + + deps = [ "../minidump", "../snapshot", - "../third_party/mini_chromium:base", "../tools:tool_support", - "../util", ] if (crashpad_is_win) { diff --git a/handler/minidump_to_upload_parameters.cc b/handler/minidump_to_upload_parameters.cc index 03c6fe14..9e26d877 100644 --- a/handler/minidump_to_upload_parameters.cc +++ b/handler/minidump_to_upload_parameters.cc @@ -17,6 +17,7 @@ #include "base/logging.h" #include "client/annotation.h" #include "snapshot/module_snapshot.h" +#include "snapshot/process_snapshot.h" #include "util/stdlib/map_insert.h" namespace crashpad { diff --git a/handler/minidump_to_upload_parameters.h b/handler/minidump_to_upload_parameters.h index 41056f70..94d396fa 100644 --- a/handler/minidump_to_upload_parameters.h +++ b/handler/minidump_to_upload_parameters.h @@ -18,10 +18,10 @@ #include <map> #include <string> -#include "snapshot/process_snapshot.h" - namespace crashpad { +class ProcessSnapshot; + //! \brief Given a ProcessSnapshot, returns a map of key-value pairs to use as //! HTTP form parameters for upload to a Breakpad crash report colleciton //! server. From b6103e157c5e927490bdfce808835709ed4dbc4d Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Mon, 15 Oct 2018 15:20:48 -0700 Subject: [PATCH 041/401] Add SystemSnapshotMinidump Only partially implemented, but we can get most of the useful stuff, including CPU Architecture. Bug: crashpad:10 Change-Id: I727eeef5770430253a45cd046a66488f743ac25a Reviewed-on: https://chromium-review.googlesource.com/c/1285033 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/BUILD.gn | 2 + .../minidump/process_snapshot_minidump.cc | 21 +- snapshot/minidump/process_snapshot_minidump.h | 6 + .../process_snapshot_minidump_test.cc | 65 ++++++ snapshot/minidump/system_snapshot_minidump.cc | 199 ++++++++++++++++++ snapshot/minidump/system_snapshot_minidump.h | 82 ++++++++ snapshot/snapshot.gyp | 2 + 7 files changed, 374 insertions(+), 3 deletions(-) create mode 100644 snapshot/minidump/system_snapshot_minidump.cc create mode 100644 snapshot/minidump/system_snapshot_minidump.h diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 85a2a500..768697db 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -48,6 +48,8 @@ static_library("snapshot") { "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", diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 97db3bdb..f50c6520 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -29,6 +29,7 @@ ProcessSnapshotMinidump::ProcessSnapshotMinidump() modules_(), unloaded_modules_(), crashpad_info_(), + system_snapshot_(), annotations_simple_map_(), file_reader_(nullptr), process_id_(static_cast<pid_t>(-1)), @@ -87,7 +88,8 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { if (!InitializeCrashpadInfo() || !InitializeMiscInfo() || !InitializeModules() || - !InitializeThreads()) { + !InitializeThreads() || + !InitializeSystemSnapshot()) { return false; } @@ -154,8 +156,7 @@ ProcessSnapshotMinidump::AnnotationsSimpleMap() const { const SystemSnapshot* ProcessSnapshotMinidump::System() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return nullptr; + return &system_snapshot_; } std::vector<const ThreadSnapshot*> ProcessSnapshotMinidump::Threads() const { @@ -435,4 +436,18 @@ bool ProcessSnapshotMinidump::InitializeThreads() { return true; } +bool ProcessSnapshotMinidump::InitializeSystemSnapshot() { + const auto& stream_it = stream_map_.find(kMinidumpStreamTypeSystemInfo); + if (stream_it == stream_map_.end()) { + return true; + } + + if (stream_it->second->DataSize < sizeof(MINIDUMP_SYSTEM_INFO)) { + LOG(ERROR) << "system info size mismatch"; + return false; + } + + return system_snapshot_.Initialize(file_reader_, stream_it->second->Rva); +} + } // namespace crashpad diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index d15ea2fb..105c5d27 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -30,6 +30,7 @@ #include "snapshot/exception_snapshot.h" #include "snapshot/memory_snapshot.h" #include "snapshot/minidump/module_snapshot_minidump.h" +#include "snapshot/minidump/system_snapshot_minidump.h" #include "snapshot/minidump/thread_snapshot_minidump.h" #include "snapshot/module_snapshot.h" #include "snapshot/process_snapshot.h" @@ -90,6 +91,10 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { // Initialize(). bool InitializeThreads(); + // Initializes data carried in a MINIDUMP_SYSTEM_INFO stream on behalf of + // Initialize(). + bool InitializeSystemSnapshot(); + // Initializes data carried in a MinidumpModuleCrashpadInfoList structure on // behalf of InitializeModules(). This makes use of MinidumpCrashpadInfo as // well, so it must be called after InitializeCrashpadInfo(). @@ -108,6 +113,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector<std::unique_ptr<internal::ThreadSnapshotMinidump>> threads_; std::vector<UnloadedModuleSnapshot> unloaded_modules_; MinidumpCrashpadInfo crashpad_info_; + internal::SystemSnapshotMinidump system_snapshot_; std::map<std::string, std::string> annotations_simple_map_; FileReaderInterface* file_reader_; // weak pid_t process_id_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index a08fbe47..9212dacb 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -506,6 +506,71 @@ TEST(ProcessSnapshotMinidump, Threads) { } } +TEST(ProcessSnapshotMinidump, System) { + const char* cpu_info = "GenuineIntel"; + const uint32_t* cpu_info_bytes = reinterpret_cast<const uint32_t*>(cpu_info); + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + MINIDUMP_SYSTEM_INFO minidump_system_info = {}; + + minidump_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureX86; + minidump_system_info.ProcessorLevel = 3; + minidump_system_info.ProcessorRevision = 3; + minidump_system_info.NumberOfProcessors = 8; + minidump_system_info.ProductType = kMinidumpOSTypeServer; + minidump_system_info.PlatformId = kMinidumpOSFuchsia; + minidump_system_info.MajorVersion = 3; + minidump_system_info.MinorVersion = 4; + minidump_system_info.BuildNumber = 56; + minidump_system_info.CSDVersionRva = WriteString(&string_file, "Snazzle"); + minidump_system_info.Cpu.X86CpuInfo.VendorId[0] = cpu_info_bytes[0]; + minidump_system_info.Cpu.X86CpuInfo.VendorId[1] = cpu_info_bytes[1]; + minidump_system_info.Cpu.X86CpuInfo.VendorId[2] = cpu_info_bytes[2]; + + MINIDUMP_DIRECTORY minidump_system_info_directory = {}; + minidump_system_info_directory.StreamType = kMinidumpStreamTypeSystemInfo; + minidump_system_info_directory.Location.DataSize = + sizeof(MINIDUMP_SYSTEM_INFO); + minidump_system_info_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + ASSERT_TRUE(string_file.Write(&minidump_system_info, + sizeof(minidump_system_info))); + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&minidump_system_info_directory, + sizeof(minidump_system_info_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + EXPECT_TRUE(string_file.SeekSet(0)); + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_TRUE(process_snapshot.Initialize(&string_file)); + + const SystemSnapshot* s = process_snapshot.System(); + + EXPECT_EQ(s->GetCPUArchitecture(), kCPUArchitectureX86); + EXPECT_EQ(s->CPURevision(), 3UL); + EXPECT_EQ(s->CPUVendor(), "GenuineIntel"); + EXPECT_EQ(s->GetOperatingSystem(), + SystemSnapshot::OperatingSystem::kOperatingSystemFuchsia); + + int major, minor, bugfix; + std::string build; + s->OSVersion(&major, &minor, &bugfix, &build); + + EXPECT_EQ(major, 3); + EXPECT_EQ(minor, 4); + EXPECT_EQ(bugfix, 56); + EXPECT_EQ(build, "Snazzle"); +} + } // namespace } // namespace test } // namespace crashpad diff --git a/snapshot/minidump/system_snapshot_minidump.cc b/snapshot/minidump/system_snapshot_minidump.cc new file mode 100644 index 00000000..356bd16c --- /dev/null +++ b/snapshot/minidump/system_snapshot_minidump.cc @@ -0,0 +1,199 @@ +// Copyright 2018 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/minidump/system_snapshot_minidump.h" + +#include "snapshot/minidump/minidump_string_reader.h" + +namespace crashpad { +namespace internal { + +SystemSnapshotMinidump::SystemSnapshotMinidump() + : SystemSnapshot(), + minidump_system_info_(), + initialized_() { +} + +SystemSnapshotMinidump::~SystemSnapshotMinidump() { +} + +bool SystemSnapshotMinidump::Initialize(FileReaderInterface* file_reader, + RVA minidump_system_info_rva) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + if (!file_reader->SeekSet(minidump_system_info_rva)) { + return false; + } + + if (!file_reader->ReadExactly(&minidump_system_info_, + sizeof(minidump_system_info_))) { + return false; + } + + if (!ReadMinidumpUTF8String(file_reader, minidump_system_info_.CSDVersionRva, + &minidump_build_name_)) { + return false; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +CPUArchitecture SystemSnapshotMinidump::GetCPUArchitecture() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + switch (minidump_system_info_.ProcessorArchitecture) { + case kMinidumpCPUArchitectureAMD64: + return kCPUArchitectureX86_64; + case kMinidumpCPUArchitectureX86: + case kMinidumpCPUArchitectureX86Win64: + return kCPUArchitectureX86; + case kMinidumpCPUArchitectureARM: + case kMinidumpCPUArchitectureARM32Win64: + return kCPUArchitectureARM; + case kMinidumpCPUArchitectureARM64: + case kMinidumpCPUArchitectureARM64Breakpad: + return kCPUArchitectureARM64; + case kMinidumpCPUArchitectureMIPS: + return kCPUArchitectureMIPSEL; + // No word on how MIPS64 is signalled + + default: + return CPUArchitecture::kCPUArchitectureUnknown; + } +} + +uint32_t SystemSnapshotMinidump::CPURevision() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_system_info_.ProcessorRevision; +} + +uint8_t SystemSnapshotMinidump::CPUCount() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_system_info_.NumberOfProcessors; +} + +std::string SystemSnapshotMinidump::CPUVendor() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (GetCPUArchitecture() == kCPUArchitectureX86) { + const char* ptr = + reinterpret_cast<const char*>(minidump_system_info_.Cpu.X86CpuInfo. + VendorId); + return std::string(ptr, ptr + (3 * sizeof(uint32_t))); + } else { + return std::string(); + } +} + +void SystemSnapshotMinidump::CPUFrequency(uint64_t* current_hz, + uint64_t* max_hz) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 +} + +uint32_t SystemSnapshotMinidump::CPUX86Signature() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return 0; +} + +uint64_t SystemSnapshotMinidump::CPUX86Features() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return 0; +} + +uint64_t SystemSnapshotMinidump::CPUX86ExtendedFeatures() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return 0; +} + +uint32_t SystemSnapshotMinidump::CPUX86Leaf7Features() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return 0; +} + +bool SystemSnapshotMinidump::CPUX86SupportsDAZ() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return false; +} + +SystemSnapshot::OperatingSystem + SystemSnapshotMinidump::GetOperatingSystem() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + switch (minidump_system_info_.PlatformId) { + case kMinidumpOSMacOSX: + return OperatingSystem::kOperatingSystemMacOSX; + case kMinidumpOSWin32s: + case kMinidumpOSWin32Windows: + case kMinidumpOSWin32NT: + return OperatingSystem::kOperatingSystemWindows; + case kMinidumpOSLinux: + return OperatingSystem::kOperatingSystemLinux; + case kMinidumpOSAndroid: + return OperatingSystem::kOperatingSystemAndroid; + case kMinidumpOSFuchsia: + return OperatingSystem::kOperatingSystemFuchsia; + default: + return OperatingSystem::kOperatingSystemUnknown; + } +} + +bool SystemSnapshotMinidump::OSServer() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return minidump_system_info_.ProductType == kMinidumpOSTypeServer; +} + +void SystemSnapshotMinidump::OSVersion(int* major, + int* minor, + int* bugfix, + std::string* build) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *major = minidump_system_info_.MajorVersion; + *minor = minidump_system_info_.MinorVersion; + *bugfix = minidump_system_info_.BuildNumber; + *build = minidump_build_name_; +} + +std::string SystemSnapshotMinidump::OSVersionFull() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return std::string(); +} + +std::string SystemSnapshotMinidump::MachineDescription() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return std::string(); +} + +bool SystemSnapshotMinidump::NXEnabled() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return false; +} + +void SystemSnapshotMinidump::TimeZone(DaylightSavingTimeStatus* dst_status, + int* standard_offset_seconds, + int* daylight_offset_seconds, + std::string* standard_name, + std::string* daylight_name) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/minidump/system_snapshot_minidump.h b/snapshot/minidump/system_snapshot_minidump.h new file mode 100644 index 00000000..71e57891 --- /dev/null +++ b/snapshot/minidump/system_snapshot_minidump.h @@ -0,0 +1,82 @@ +// Copyright 2018 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_MINIDUMP_SYSTEM_SNAPSHOT_MINIDUMP_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_SYSTEM_SNAPSHOT_MINIDUMP_H_ + +#include <windows.h> + +#include "base/macros.h" +#include "minidump/minidump_extensions.h" +#include "snapshot/system_snapshot.h" +#include "util/file/file_reader.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { + +//! \brief A SystemSnapshot based on a minidump file. +class SystemSnapshotMinidump : public SystemSnapshot { + public: + SystemSnapshotMinidump(); + ~SystemSnapshotMinidump() override; + + //! \brief Initializes the object. + //! + //! \param[in] file_reader A file reader corresponding to a minidump file. + //! The file reader must support seeking. + //! \param[in] minidump_system_info_rva The file offset in \a file_reader at + //! which the thread’s MINIDUMP_SYSTEM_INFO structure is located. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! an appropriate message logged. + bool Initialize(FileReaderInterface* file_reader, + RVA minidump_system_info_rva); + + CPUArchitecture GetCPUArchitecture() const override; + uint32_t CPURevision() const override; + uint8_t CPUCount() const override; + std::string CPUVendor() const override; + void CPUFrequency(uint64_t* current_hz, uint64_t* max_hz) const override; + uint32_t CPUX86Signature() const override; + uint64_t CPUX86Features() const override; + uint64_t CPUX86ExtendedFeatures() const override; + uint32_t CPUX86Leaf7Features() const override; + bool CPUX86SupportsDAZ() const override; + OperatingSystem GetOperatingSystem() const override; + bool OSServer() const override; + void OSVersion(int* major, + int* minor, + int* bugfix, + std::string* build) const override; + std::string OSVersionFull() const override; + std::string MachineDescription() const override; + bool NXEnabled() const override; + void TimeZone(DaylightSavingTimeStatus* dst_status, + int* standard_offset_seconds, + int* daylight_offset_seconds, + std::string* standard_name, + std::string* daylight_name) const override; + private: + MINIDUMP_SYSTEM_INFO minidump_system_info_; + std::string minidump_build_name_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(SystemSnapshotMinidump); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_SYSTEM_SNAPSHOT_MINIDUMP_H_ diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 7fb4ba82..4c8a5cbf 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -119,6 +119,8 @@ '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', From 8d17d5b4cf33f225cc13c865e9e7499272a5de02 Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Tue, 16 Oct 2018 12:23:21 -0700 Subject: [PATCH 042/401] Decode Thread Context in minidump We can now get the CPU state for threads from minidump snapshots. Bug: crashpad:10 Change-Id: I6bef2b033f7b04fcfa64c114be94064f3e0ae775 Reviewed-on: https://chromium-review.googlesource.com/c/1285034 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- .../minidump/process_snapshot_minidump.cc | 14 +- snapshot/minidump/process_snapshot_minidump.h | 1 + .../process_snapshot_minidump_test.cc | 324 ++++++++++++++++++ snapshot/minidump/thread_snapshot_minidump.cc | 274 ++++++++++++++- snapshot/minidump/thread_snapshot_minidump.h | 18 +- 5 files changed, 623 insertions(+), 8 deletions(-) diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index f50c6520..a9bd0f04 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -30,6 +30,7 @@ ProcessSnapshotMinidump::ProcessSnapshotMinidump() unloaded_modules_(), crashpad_info_(), system_snapshot_(), + arch_(CPUArchitecture::kCPUArchitectureUnknown), annotations_simple_map_(), file_reader_(nullptr), process_id_(static_cast<pid_t>(-1)), @@ -88,8 +89,8 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { if (!InitializeCrashpadInfo() || !InitializeMiscInfo() || !InitializeModules() || - !InitializeThreads() || - !InitializeSystemSnapshot()) { + !InitializeSystemSnapshot() || + !InitializeThreads()) { return false; } @@ -426,7 +427,7 @@ bool ProcessSnapshotMinidump::InitializeThreads() { thread_index * sizeof(MINIDUMP_THREAD); auto thread = std::make_unique<internal::ThreadSnapshotMinidump>(); - if (!thread->Initialize(file_reader_, thread_rva)) { + if (!thread->Initialize(file_reader_, thread_rva, arch_)) { return false; } @@ -447,7 +448,12 @@ bool ProcessSnapshotMinidump::InitializeSystemSnapshot() { return false; } - return system_snapshot_.Initialize(file_reader_, stream_it->second->Rva); + if (!system_snapshot_.Initialize(file_reader_, stream_it->second->Rva)) { + return false; + } + + arch_ = system_snapshot_.GetCPUArchitecture(); + return true; } } // namespace crashpad diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 105c5d27..2ef23a68 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -114,6 +114,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector<UnloadedModuleSnapshot> unloaded_modules_; MinidumpCrashpadInfo crashpad_info_; internal::SystemSnapshotMinidump system_snapshot_; + CPUArchitecture arch_; std::map<std::string, std::string> annotations_simple_map_; FileReaderInterface* file_reader_; // weak pid_t process_id_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 9212dacb..b710f028 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -21,6 +21,7 @@ #include <memory> #include "gtest/gtest.h" +#include "minidump/minidump_context.h" #include "snapshot/minidump/minidump_annotation_reader.h" #include "snapshot/module_snapshot.h" #include "util/file/string_file.h" @@ -571,6 +572,329 @@ TEST(ProcessSnapshotMinidump, System) { EXPECT_EQ(build, "Snazzle"); } +TEST(ProcessSnapshotMinidump, ThreadContextARM64) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + MINIDUMP_SYSTEM_INFO minidump_system_info = {}; + + minidump_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureARM64; + minidump_system_info.ProductType = kMinidumpOSTypeServer; + minidump_system_info.PlatformId = kMinidumpOSFuchsia; + minidump_system_info.CSDVersionRva = WriteString(&string_file, ""); + + MINIDUMP_DIRECTORY minidump_system_info_directory = {}; + minidump_system_info_directory.StreamType = kMinidumpStreamTypeSystemInfo; + minidump_system_info_directory.Location.DataSize = + sizeof(MINIDUMP_SYSTEM_INFO); + minidump_system_info_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + ASSERT_TRUE(string_file.Write(&minidump_system_info, + sizeof(minidump_system_info))); + + MINIDUMP_THREAD minidump_thread = {}; + uint32_t minidump_thread_count = 1; + + minidump_thread.ThreadId = 42; + minidump_thread.Teb = 24; + + MinidumpContextARM64 minidump_context; + + minidump_context.context_flags = kMinidumpContextARM64Full; + + minidump_context.cpsr = 0; + + for (int i = 0; i < 29; i++) { + minidump_context.regs[i] = i + 1; + } + + minidump_context.fp = 30; + minidump_context.lr = 31; + minidump_context.sp = 32; + minidump_context.pc = 33; + + for (int i = 0; i < 32; i++) { + minidump_context.fpsimd[i].lo = i * 2 + 34; + minidump_context.fpsimd[i].hi = i * 2 + 35; + } + + minidump_context.fpcr = 98; + minidump_context.fpsr = 99; + + for (int i = 0; i < 8; i++) { + minidump_context.bcr[i] = i * 2 + 100; + minidump_context.bvr[i] = i * 2 + 101; + } + + for (int i = 0; i < 2; i++) { + minidump_context.wcr[i] = i * 2 + 115; + minidump_context.wvr[i] = i * 2 + 116; + } + + minidump_thread.ThreadContext.DataSize = sizeof(minidump_context); + minidump_thread.ThreadContext.Rva = static_cast<RVA>(string_file.SeekGet()); + + EXPECT_TRUE(string_file.Write(&minidump_context, sizeof(minidump_context))); + + MINIDUMP_DIRECTORY minidump_thread_list_directory = {}; + minidump_thread_list_directory.StreamType = kMinidumpStreamTypeThreadList; + minidump_thread_list_directory.Location.DataSize = + sizeof(MINIDUMP_THREAD_LIST) + + minidump_thread_count * sizeof(MINIDUMP_THREAD); + minidump_thread_list_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + // Fields in MINIDUMP_THREAD_LIST. + EXPECT_TRUE( + string_file.Write(&minidump_thread_count, sizeof(minidump_thread_count))); + EXPECT_TRUE(string_file.Write(&minidump_thread, sizeof(minidump_thread))); + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&minidump_system_info_directory, + sizeof(minidump_system_info_directory))); + ASSERT_TRUE(string_file.Write(&minidump_thread_list_directory, + sizeof(minidump_thread_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<const ThreadSnapshot*> threads = process_snapshot.Threads(); + ASSERT_EQ(threads.size(), minidump_thread_count); + + const CPUContext* ctx_generic = threads[0]->Context(); + + ASSERT_EQ(ctx_generic->architecture, CPUArchitecture::kCPUArchitectureARM64); + + const CPUContextARM64* ctx = ctx_generic->arm64; + + EXPECT_EQ(ctx->pstate, 0UL); + + for (unsigned int i = 0; i < 31; i++) { + EXPECT_EQ(ctx->regs[i], i + 1); + } + + EXPECT_EQ(ctx->sp, 32UL); + EXPECT_EQ(ctx->pc, 33UL); + EXPECT_EQ(ctx->fpcr, 98UL); + EXPECT_EQ(ctx->fpsr, 99UL); + + for (unsigned int i = 0; i < 32; i++) { + EXPECT_EQ(ctx->fpsimd[i].lo, i * 2 + 34); + EXPECT_EQ(ctx->fpsimd[i].hi, i * 2 + 35); + } +} + +TEST(ProcessSnapshotMinidump, ThreadContextX86_64) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + MINIDUMP_SYSTEM_INFO minidump_system_info = {}; + + minidump_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureAMD64; + minidump_system_info.ProductType = kMinidumpOSTypeServer; + minidump_system_info.PlatformId = kMinidumpOSFuchsia; + minidump_system_info.CSDVersionRva = WriteString(&string_file, ""); + + MINIDUMP_DIRECTORY minidump_system_info_directory = {}; + minidump_system_info_directory.StreamType = kMinidumpStreamTypeSystemInfo; + minidump_system_info_directory.Location.DataSize = + sizeof(MINIDUMP_SYSTEM_INFO); + minidump_system_info_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + ASSERT_TRUE(string_file.Write(&minidump_system_info, + sizeof(minidump_system_info))); + + MINIDUMP_THREAD minidump_thread = {}; + uint32_t minidump_thread_count = 1; + + minidump_thread.ThreadId = 42; + minidump_thread.Teb = 24; + + MinidumpContextAMD64 minidump_context; + + minidump_context.context_flags = kMinidumpContextAMD64Full; + + minidump_context.mx_csr = 0; + minidump_context.cs = 1; + minidump_context.ds = 2; + minidump_context.es = 3; + minidump_context.fs = 4; + minidump_context.gs = 5; + minidump_context.ss = 6; + minidump_context.eflags = 7; + minidump_context.dr0 = 8; + minidump_context.dr1 = 9; + minidump_context.dr2 = 10; + minidump_context.dr3 = 11; + minidump_context.dr6 = 12; + minidump_context.dr7 = 13; + minidump_context.rax = 14; + minidump_context.rcx = 15; + minidump_context.rdx = 16; + minidump_context.rbx = 17; + minidump_context.rsp = 18; + minidump_context.rbp = 19; + minidump_context.rsi = 20; + minidump_context.rdi = 21; + minidump_context.r8 = 22; + minidump_context.r9 = 23; + minidump_context.r10 = 24; + minidump_context.r11 = 25; + minidump_context.r12 = 26; + minidump_context.r13 = 27; + minidump_context.r14 = 28; + minidump_context.r15 = 29; + minidump_context.rip = 30; + minidump_context.vector_control = 31; + minidump_context.debug_control = 32; + minidump_context.last_branch_to_rip = 33; + minidump_context.last_branch_from_rip = 34; + minidump_context.last_exception_to_rip = 35; + minidump_context.last_exception_from_rip = 36; + minidump_context.fxsave.fcw = 37; + minidump_context.fxsave.fsw = 38; + minidump_context.fxsave.ftw = 39; + minidump_context.fxsave.reserved_1 = 40; + minidump_context.fxsave.fop = 41; + minidump_context.fxsave.fpu_ip_64 = 42; + minidump_context.fxsave.fpu_dp_64 = 43; + + for (size_t i = 0; i < arraysize(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 < arraysize(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 < arraysize(minidump_context.fxsave.st_mm); i++) { + for (uint8_t j = 0; + j < arraysize(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 < arraysize(minidump_context.fxsave.xmm); i++) { + for (uint8_t j = 0; j < arraysize(minidump_context.fxsave.xmm[0]); j++) { + minidump_context.fxsave.xmm[i][j] = j + 1; + } + } + + minidump_thread.ThreadContext.DataSize = sizeof(minidump_context); + minidump_thread.ThreadContext.Rva = static_cast<RVA>(string_file.SeekGet()); + + EXPECT_TRUE(string_file.Write(&minidump_context, sizeof(minidump_context))); + + MINIDUMP_DIRECTORY minidump_thread_list_directory = {}; + minidump_thread_list_directory.StreamType = kMinidumpStreamTypeThreadList; + minidump_thread_list_directory.Location.DataSize = + sizeof(MINIDUMP_THREAD_LIST) + + minidump_thread_count * sizeof(MINIDUMP_THREAD); + minidump_thread_list_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + // Fields in MINIDUMP_THREAD_LIST. + EXPECT_TRUE( + string_file.Write(&minidump_thread_count, sizeof(minidump_thread_count))); + EXPECT_TRUE(string_file.Write(&minidump_thread, sizeof(minidump_thread))); + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&minidump_system_info_directory, + sizeof(minidump_system_info_directory))); + ASSERT_TRUE(string_file.Write(&minidump_thread_list_directory, + sizeof(minidump_thread_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<const ThreadSnapshot*> threads = process_snapshot.Threads(); + ASSERT_EQ(threads.size(), minidump_thread_count); + + const CPUContext* ctx_generic = threads[0]->Context(); + + ASSERT_EQ(ctx_generic->architecture, CPUArchitecture::kCPUArchitectureX86_64); + + const CPUContextX86_64* ctx = ctx_generic->x86_64; + EXPECT_EQ(ctx->cs, 1); + EXPECT_EQ(ctx->fs, 4); + EXPECT_EQ(ctx->gs, 5); + EXPECT_EQ(ctx->rflags, 7UL); + EXPECT_EQ(ctx->dr0, 8UL); + EXPECT_EQ(ctx->dr1, 9U); + EXPECT_EQ(ctx->dr2, 10U); + EXPECT_EQ(ctx->dr3, 11U); + EXPECT_EQ(ctx->dr4, 12U); + EXPECT_EQ(ctx->dr5, 13U); + EXPECT_EQ(ctx->dr6, 12U); + EXPECT_EQ(ctx->dr7, 13U); + EXPECT_EQ(ctx->rax, 14U); + EXPECT_EQ(ctx->rcx, 15U); + EXPECT_EQ(ctx->rdx, 16U); + EXPECT_EQ(ctx->rbx, 17U); + EXPECT_EQ(ctx->rsp, 18U); + EXPECT_EQ(ctx->rbp, 19U); + EXPECT_EQ(ctx->rsi, 20U); + EXPECT_EQ(ctx->rdi, 21U); + EXPECT_EQ(ctx->r8, 22U); + EXPECT_EQ(ctx->r9, 23U); + EXPECT_EQ(ctx->r10, 24U); + EXPECT_EQ(ctx->r11, 25U); + EXPECT_EQ(ctx->r12, 26U); + EXPECT_EQ(ctx->r13, 27U); + EXPECT_EQ(ctx->r14, 28U); + EXPECT_EQ(ctx->r15, 29U); + EXPECT_EQ(ctx->rip, 30U); + EXPECT_EQ(ctx->fxsave.fcw, 37U); + EXPECT_EQ(ctx->fxsave.fsw, 38U); + EXPECT_EQ(ctx->fxsave.ftw, 39U); + EXPECT_EQ(ctx->fxsave.reserved_1, 40U); + EXPECT_EQ(ctx->fxsave.fop, 41U); + EXPECT_EQ(ctx->fxsave.fpu_ip_64, 42U); + EXPECT_EQ(ctx->fxsave.fpu_dp_64, 43U); + + for (uint8_t i = 0; i < arraysize(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 < arraysize(ctx->fxsave.st_mm); i++) { + for (uint8_t j = 0; + j < arraysize(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 < arraysize(ctx->fxsave.xmm); i++) { + for (uint8_t j = 0; j < arraysize(ctx->fxsave.xmm[0]); j++) { + EXPECT_EQ(ctx->fxsave.xmm[i][j], j + 1); + } + } +} + } // namespace } // namespace test } // namespace crashpad diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc index 9bf2b718..458586d3 100644 --- a/snapshot/minidump/thread_snapshot_minidump.cc +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -14,6 +14,10 @@ #include "snapshot/minidump/thread_snapshot_minidump.h" +#include <string.h> + +#include "minidump/minidump_context.h" + namespace crashpad { namespace internal { @@ -27,8 +31,13 @@ ThreadSnapshotMinidump::~ThreadSnapshotMinidump() { } bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, - RVA minidump_thread_rva) { + RVA minidump_thread_rva, + CPUArchitecture arch) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + std::vector<unsigned char> minidump_context; + + context_.architecture = arch; + if (!file_reader->SeekSet(minidump_thread_rva)) { return false; } @@ -37,10 +46,270 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, return false; } + if (!file_reader->SeekSet(minidump_thread_.ThreadContext.Rva)) { + return false; + } + + minidump_context.resize(minidump_thread_.ThreadContext.DataSize); + + if (!file_reader->ReadExactly(minidump_context.data(), + minidump_context.size())) { + return false; + } + + if (!InitializeContext(minidump_context)) { + return false; + } + INITIALIZATION_STATE_SET_VALID(initialized_); return true; } +bool ThreadSnapshotMinidump::InitializeContext( + const std::vector<unsigned char>& minidump_context) { + if (minidump_context.size() == 0) { + // Thread has no context. + context_.architecture = CPUArchitecture::kCPUArchitectureUnknown; + return true; + } + + if (context_.architecture == CPUArchitecture::kCPUArchitectureX86) { + LOG(WARNING) << "Snapshot X86 context support has no unit tests."; + context_memory_.resize(sizeof(CPUContextX86)); + context_.x86 = reinterpret_cast<CPUContextX86*>(context_memory_.data()); + const MinidumpContextX86* src = + reinterpret_cast<const MinidumpContextX86*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextX86)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextX86)) { + return false; + } + + if (src->context_flags & kMinidumpContextX86Extended) { + context_.x86->fxsave = src->fxsave; + } else if (src->context_flags & kMinidumpContextX86FloatingPoint) { + CPUContextX86::FsaveToFxsave(src->fsave, &context_.x86->fxsave); + } + + context_.x86->eax = src->eax; + context_.x86->ebx = src->ebx; + context_.x86->ecx = src->ecx; + context_.x86->edx = src->edx; + context_.x86->edi = src->edi; + context_.x86->esi = src->esi; + context_.x86->ebp = src->ebp; + context_.x86->esp = src->esp; + context_.x86->eip = src->eip; + context_.x86->eflags = src->eflags; + context_.x86->cs = static_cast<uint16_t>(src->cs); + context_.x86->ds = static_cast<uint16_t>(src->ds); + context_.x86->es = static_cast<uint16_t>(src->es); + context_.x86->fs = static_cast<uint16_t>(src->fs); + context_.x86->gs = static_cast<uint16_t>(src->gs); + context_.x86->ss = static_cast<uint16_t>(src->ss); + context_.x86->dr0 = src->dr0; + context_.x86->dr1 = src->dr1; + context_.x86->dr2 = src->dr2; + context_.x86->dr3 = src->dr3; + context_.x86->dr6 = src->dr6; + context_.x86->dr7 = src->dr7; + + // Minidump passes no value for dr4/5. Our output context has space for + // them. According to spec they're obsolete, but when present read as + // aliases for dr6/7, so we'll do this. + context_.x86->dr4 = src->dr6; + context_.x86->dr5 = src->dr7; + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureX86_64) { + context_memory_.resize(sizeof(CPUContextX86_64)); + context_.x86_64 = + reinterpret_cast<CPUContextX86_64*>(context_memory_.data()); + const MinidumpContextAMD64* src = + reinterpret_cast<const MinidumpContextAMD64*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextAMD64)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextAMD64)) { + return false; + } + + context_.x86_64->fxsave = src->fxsave; + context_.x86_64->cs = src->cs; + context_.x86_64->fs = src->fs; + context_.x86_64->gs = src->gs; + context_.x86_64->rflags = src->eflags; + context_.x86_64->dr0 = src->dr0; + context_.x86_64->dr1 = src->dr1; + context_.x86_64->dr2 = src->dr2; + context_.x86_64->dr3 = src->dr3; + context_.x86_64->dr6 = src->dr6; + context_.x86_64->dr7 = src->dr7; + context_.x86_64->rax = src->rax; + context_.x86_64->rcx = src->rcx; + context_.x86_64->rdx = src->rdx; + context_.x86_64->rbx = src->rbx; + context_.x86_64->rsp = src->rsp; + context_.x86_64->rbp = src->rbp; + context_.x86_64->rsi = src->rsi; + context_.x86_64->rdi = src->rdi; + context_.x86_64->r8 = src->r8; + context_.x86_64->r9 = src->r9; + context_.x86_64->r10 = src->r10; + context_.x86_64->r11 = src->r11; + context_.x86_64->r12 = src->r12; + context_.x86_64->r13 = src->r13; + context_.x86_64->r14 = src->r14; + context_.x86_64->r15 = src->r15; + context_.x86_64->rip = src->rip; + + // See comments on x86 above. + context_.x86_64->dr4 = src->dr6; + context_.x86_64->dr5 = src->dr7; + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM) { + LOG(WARNING) << "Snapshot ARM32 context support has no unit tests."; + context_memory_.resize(sizeof(CPUContextARM)); + context_.arm = reinterpret_cast<CPUContextARM*>(context_memory_.data()); + const MinidumpContextARM* src = + reinterpret_cast<const MinidumpContextARM*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextARM)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextARM)) { + return false; + } + + for (size_t i = 0; i < arraysize(src->regs); i++) { + context_.arm->regs[i] = src->regs[i]; + } + + context_.arm->fp = src->fp; + context_.arm->ip = src->ip; + context_.arm->sp = src->sp; + context_.arm->lr = src->lr; + context_.arm->pc = src->pc; + context_.arm->cpsr = src->cpsr; + context_.arm->vfp_regs.fpscr = src->fpscr; + + for (size_t i = 0; i < arraysize(src->vfp); i++) { + context_.arm->vfp_regs.vfp[i] = src->vfp[i]; + } + + context_.arm->have_fpa_regs = false; + context_.arm->have_vfp_regs = + !!(src->context_flags & kMinidumpContextARMVFP); + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM64) { + context_memory_.resize(sizeof(CPUContextARM64)); + context_.arm64= reinterpret_cast<CPUContextARM64*>(context_memory_.data()); + const MinidumpContextARM64* src = + reinterpret_cast<const MinidumpContextARM64*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextARM64)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextARM64)) { + return false; + } + + for (size_t i = 0; i < arraysize(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 < arraysize(src->fpsimd); i++) { + context_.arm64->fpsimd[i] = src->fpsimd[i]; + } + + context_.arm64->sp = src->sp; + context_.arm64->pc = src->pc; + context_.arm64->fpcr = src->fpcr; + context_.arm64->fpsr = src->fpsr; + + // Seems we don't get a full PSTATE but it looks like this assignment + // should give something useful at least. + context_.arm64->pstate = src->cpsr; + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPSEL) { + LOG(WARNING) << "Snapshot MIPS context support has no unit tests."; + context_memory_.resize(sizeof(CPUContextMIPS)); + context_.mipsel = reinterpret_cast<CPUContextMIPS*>(context_memory_.data()); + const MinidumpContextMIPS* src = + reinterpret_cast<const MinidumpContextMIPS*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextMIPS)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextMIPS)) { + return false; + } + + for (size_t i = 0; i < arraysize(src->regs); i++) { + context_.mipsel->regs[i] = src->regs[i]; + } + + context_.mipsel->mdhi = static_cast<uint32_t>(src->mdhi); + context_.mipsel->mdlo = static_cast<uint32_t>(src->mdlo); + context_.mipsel->dsp_control = src->dsp_control; + + for (size_t i = 0; i < arraysize(src->hi); i++) { + context_.mipsel->hi[i] = src->hi[i]; + context_.mipsel->lo[i] = src->lo[i]; + } + + context_.mipsel->cp0_epc = static_cast<uint32_t>(src->epc); + context_.mipsel->cp0_badvaddr = static_cast<uint32_t>(src->badvaddr); + context_.mipsel->cp0_status = src->status; + context_.mipsel->cp0_cause = src->cause; + context_.mipsel->fpcsr = src->fpcsr; + context_.mipsel->fir = src->fir; + + memcpy(&context_.mipsel->fpregs, &src->fpregs, sizeof(src->fpregs)); + } else if (context_.architecture == + CPUArchitecture::kCPUArchitectureMIPS64EL) { + LOG(WARNING) << "Snapshot MIPS64 context support has no unit tests."; + context_memory_.resize(sizeof(CPUContextMIPS64)); + context_.mips64 = + reinterpret_cast<CPUContextMIPS64*>(context_memory_.data()); + const MinidumpContextMIPS64* src = + reinterpret_cast<const MinidumpContextMIPS64*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextMIPS64)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextMIPS64)) { + return false; + } + + for (size_t i = 0; i < arraysize(src->regs); i++) { + context_.mips64->regs[i] = src->regs[i]; + } + + context_.mips64->mdhi = src->mdhi; + context_.mips64->mdlo = src->mdlo; + context_.mips64->dsp_control = src->dsp_control; + + for (size_t i = 0; i < arraysize(src->hi); i++) { + context_.mips64->hi[i] = src->hi[i]; + context_.mips64->lo[i] = src->lo[i]; + } + + context_.mips64->cp0_epc = src->epc; + context_.mips64->cp0_badvaddr = src->badvaddr; + context_.mips64->cp0_status = src->status; + context_.mips64->cp0_cause = src->cause; + context_.mips64->fpcsr = src->fpcsr; + context_.mips64->fir = src->fir; + + memcpy(&context_.mips64->fpregs, &src->fpregs, sizeof(src->fpregs)); + } + + // If we fell through, Architecture is listed as "unknown". + return true; +} + uint64_t ThreadSnapshotMinidump::ThreadID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return minidump_thread_.ThreadId; @@ -63,8 +332,7 @@ int ThreadSnapshotMinidump::Priority() const { const CPUContext* ThreadSnapshotMinidump::Context() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return nullptr; + return &context_; } const MemorySnapshot* ThreadSnapshotMinidump::Stack() const { diff --git a/snapshot/minidump/thread_snapshot_minidump.h b/snapshot/minidump/thread_snapshot_minidump.h index 18a17b28..338f2341 100644 --- a/snapshot/minidump/thread_snapshot_minidump.h +++ b/snapshot/minidump/thread_snapshot_minidump.h @@ -19,6 +19,7 @@ #include "minidump/minidump_extensions.h" #include "snapshot/thread_snapshot.h" +#include "snapshot/cpu_context.h" #include "util/file/file_reader.h" #include "util/misc/initialization_state_dcheck.h" @@ -37,10 +38,13 @@ class ThreadSnapshotMinidump : public ThreadSnapshot { //! The file reader must support seeking. //! \param[in] minidump_thread_rva The file offset in \a file_reader at which //! 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. //! //! \return `true` if the snapshot could be created, `false` otherwise with //! an appropriate message logged. - bool Initialize(FileReaderInterface* file_reader, RVA minidump_thread_rva); + bool Initialize(FileReaderInterface* file_reader, RVA minidump_thread_rva, + CPUArchitecture arch); const CPUContext* Context() const override; const MemorySnapshot* Stack() const override; @@ -51,8 +55,20 @@ class ThreadSnapshotMinidump : public ThreadSnapshot { std::vector<const MemorySnapshot*> ExtraMemory() const override; private: + //! \brief Initializes the CPU Context + //! + //! \param[in] minidump_context the raw bytes of the context data from the + //! minidump file. + //! + //! \return `true` if the context could be decoded without error. + bool InitializeContext(const std::vector<unsigned char>& minidump_context); + MINIDUMP_THREAD minidump_thread_; + CPUContext context_; + std::vector<unsigned char> context_memory_; InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ThreadSnapshotMinidump); }; } // namespace internal From 3b68e1278952c1befa5b6778b468cf6bbab9bfbe Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Wed, 17 Oct 2018 15:31:34 -0700 Subject: [PATCH 043/401] Update bot link for new LUCI console Fix link to bots to point to LUCI instead of Buildbot. Bug: chromium:892712 TBR: jperaza@chromium.org Change-Id: I0d1b6085327750ca4c975771d0422089ab6da07b Reviewed-on: https://chromium-review.googlesource.com/c/1287231 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d74c1bd5..b20777bb 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ https://chromium.googlesource.com/crashpad/crashpad. * Bugs can be reported at the [Crashpad issue tracker](https://crashpad.chromium.org/bug/). - * The [Crashpad Buildbots](https://build.chromium.org/p/client.crashpad) + * The [Crashpad bots](https://ci.chromium.org/p/crashpad/g/main/console) perform automated builds and tests. * [crashpad-dev](https://groups.google.com/a/chromium.org/group/crashpad-dev) is the Crashpad developers’ mailing list. From c7f1543dd388d5015fb6f815b35cedd2dbe478d0 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Wed, 17 Oct 2018 15:59:56 -0700 Subject: [PATCH 044/401] Don't auto-generate gyp build files any more We were still generating gyp build files on the bots, and then using the GN build. There's some not-working logic in gyp to find the hermetic Xcode SDK that the new bots are using, so just avoid generating the gyp build now, since we're not using it anyway. (My understanding is that the Android build uses build/gyp_crashpad_android.py instead not build/gyp_crashpad.py. But there's no Android bots in any case, so it shouldn't be a problem for that.) Bug: chromium:892712 Change-Id: Id290f0ddb8d9067deae10b32ab4a8f08a3954ed0 Reviewed-on: https://chromium-review.googlesource.com/c/1287234 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- DEPS | 5 ----- 1 file changed, 5 deletions(-) diff --git a/DEPS b/DEPS index 8a1ba5ab..61b80652 100644 --- a/DEPS +++ b/DEPS @@ -212,11 +212,6 @@ hooks = [ 'crashpad/build/install_linux_sysroot.py', ], }, - { - 'name': 'gyp', - 'pattern': '\.gypi?$', - 'action': ['python', 'crashpad/build/gyp_crashpad.py'], - }, ] recursedeps = [ From 289be79a33f2270ea0ade1b2daeda94adfd00f5e Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 18 Oct 2018 09:50:38 -0700 Subject: [PATCH 045/401] Roll mini_chromium to 3577ffd 3577ffd win: Add additional detection for toolchain TBR=mark@chromium.org Bug: chromium:892712 Change-Id: I0674c8068dac089e014da5b982ef672f57d80b9e Reviewed-on: https://chromium-review.googlesource.com/c/1289089 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 61b80652..123daf62 100644 --- a/DEPS +++ b/DEPS @@ -30,7 +30,7 @@ deps = { '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '8d641e30a8b12088649606b912c2bc4947419ccc', + '3577ffda752e26e506bb4971a8fb8bc67189ad1e', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 196897eb080437e691253b77dd93020abbd2d2bd Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 18 Oct 2018 15:12:15 -0700 Subject: [PATCH 046/401] Remove win buildbot bots from cq config TBR=iannucci@chromium.org Bug: chromium:892712 Change-Id: I11af294ec2d088dc6e846291102077a9fa74d663 Reviewed-on: https://chromium-review.googlesource.com/c/1289714 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- infra/config/cq.cfg | 9 --------- 1 file changed, 9 deletions(-) diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg index 1fc33243..e47cce08 100644 --- a/infra/config/cq.cfg +++ b/infra/config/cq.cfg @@ -31,15 +31,6 @@ verifiers { dry_run_access_list: "project-crashpad-tryjob-access" } try_job { - buckets { - name: "master.client.crashpad" - builders { name: "crashpad_try_win_dbg" } - builders { name: "crashpad_try_win_rel" } - # https://crbug.com/743139 - disabled until we can move these to swarming, - # at which point we can just remove them. - #builders { name: "crashpad_try_win_x86_dbg" } - #builders { name: "crashpad_try_win_x86_rel" } - } buckets { name: "luci.crashpad.try" builders { name: "crashpad_try_mac_dbg" } From 2951fbde523f232447f46a0cda9653c70b4db3de Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 18 Oct 2018 15:32:12 -0700 Subject: [PATCH 047/401] Remove cq_name from cq.cfg, no longer required/allowed Also add cq PRESUBMIT to validate future changes. TBR=iannucci@chromium.org Bug: chromium:892712 Change-Id: Ia2b3fe9550857939843fda738068aabec26942e2 Reviewed-on: https://chromium-review.googlesource.com/c/1289715 Reviewed-by: Scott Graham <scottmg@chromium.org> --- infra/config/PRESUBMIT.py | 19 +++++++++++++++++++ infra/config/cq.cfg | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 infra/config/PRESUBMIT.py diff --git a/infra/config/PRESUBMIT.py b/infra/config/PRESUBMIT.py new file mode 100644 index 00000000..c2317e1b --- /dev/null +++ b/infra/config/PRESUBMIT.py @@ -0,0 +1,19 @@ +# Copyright 2018 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. + +def CheckChangeOnUpload(input_api, output_api): + return input_api.canned_checks.CheckChangedLUCIConfigs(input_api, output_api) + +def CheckChangeOnCommit(input_api, output_api): + return input_api.canned_checks.CheckChangedLUCIConfigs(input_api, output_api) diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg index e47cce08..c6c8a396 100644 --- a/infra/config/cq.cfg +++ b/infra/config/cq.cfg @@ -16,7 +16,6 @@ # documentation of this file format. version: 1 -cq_name: "crashpad" cq_status_url: "https://chromium-cq-status.appspot.com" # This is required for gerrit projects. From fa96a04fc64dd1d1cb34a1c38c32dc21c9f26c5e Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 18 Oct 2018 15:34:12 -0700 Subject: [PATCH 048/401] Add .vpython spec to add pywintypes to luci runs TBR=iannucci@chromium.org Bug: chromium:892712 Change-Id: Iae097ccad3989a26f6f67e9151c41e2360f6e474 Reviewed-on: https://chromium-review.googlesource.com/c/1289713 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- .vpython | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .vpython diff --git a/.vpython b/.vpython new file mode 100644 index 00000000..c2001fc5 --- /dev/null +++ b/.vpython @@ -0,0 +1,32 @@ +# Copyright 2018 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/pypiwin32/${vpython_platform}" + version: "version:219" + match_tag: < + platform: "win32" + > + match_tag: < + platform: "win_amd64" + > +> From 456476c3f62e8f7dd07a933d3da0f29352498b96 Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Thu, 18 Oct 2018 15:53:38 -0700 Subject: [PATCH 049/401] Add ReadMinidumpUTF16String Change-Id: If0f33e39bad29ade28eaab8dc064318253e7e70e Reviewed-on: https://chromium-review.googlesource.com/c/1290170 Commit-Queue: Casey Dahlin <sadmac@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/minidump/minidump_string_reader.cc | 38 +++++++++++++++++++-- snapshot/minidump/minidump_string_reader.h | 19 +++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/snapshot/minidump/minidump_string_reader.cc b/snapshot/minidump/minidump_string_reader.cc index 4a5cb136..d642e9d4 100644 --- a/snapshot/minidump/minidump_string_reader.cc +++ b/snapshot/minidump/minidump_string_reader.cc @@ -17,14 +17,18 @@ #include <stdint.h> #include "base/logging.h" +#include "base/strings/utf_string_conversions.h" #include "minidump/minidump_extensions.h" namespace crashpad { namespace internal { -bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, +namespace { + +template<typename StringType> +bool ReadMinidumpString(FileReaderInterface* file_reader, RVA rva, - std::string* string) { + StringType* string) { if (rva == 0) { string->clear(); return true; @@ -39,7 +43,7 @@ bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, return false; } - std::string local_string(string_size, '\0'); + StringType local_string(string_size / sizeof((*string)[0]), '\0'); if (!file_reader->ReadExactly(&local_string[0], string_size)) { return false; } @@ -48,5 +52,33 @@ bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, return true; } +} // namespace + +bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, + RVA rva, + std::string* string) { + return ReadMinidumpString(file_reader, rva, string); +} + +bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, + RVA rva, + base::string16* string) { + return ReadMinidumpString(file_reader, rva, string); +} + +bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, + RVA rva, + std::string* string) { + base::string16 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 e5667ec2..b7ecdac3 100644 --- a/snapshot/minidump/minidump_string_reader.h +++ b/snapshot/minidump/minidump_string_reader.h @@ -20,6 +20,7 @@ #include <string> +#include "base/strings/string16.h" #include "util/file/file_reader.h" namespace crashpad { @@ -34,6 +35,24 @@ bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, RVA 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. +//! +//! \return `true` on success, with \a string set. `false` on failure, with a +//! message logged. +bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, + RVA rva, + base::string16* string); + +//! \brief Reads a MinidumpUTF16String from a minidump file at offset \a rva in +//! \a file_reader, and returns it in \a string. +//! +//! \return `true` on success, with \a string set. `false` on failure, with a +//! message logged. +bool ReadMinidumpUTF16String(FileReaderInterface* file_reader, + RVA rva, + std::string* string); + } // namespace internal } // namespace crashpad From 95b177e79398fe3fd042936ae5bf22c6252a7720 Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Thu, 18 Oct 2018 17:11:02 -0700 Subject: [PATCH 050/401] Flesh out ModuleSnapshotMinidump Most of the methods are implemented now. Only a couple stragglers left. Bug: crashpad:10 Change-Id: Ib0d2f7571d9a0e7bab1a24c66355c05804b63367 Reviewed-on: https://chromium-review.googlesource.com/c/1290171 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Casey Dahlin <sadmac@google.com> --- snapshot/minidump/module_snapshot_minidump.cc | 80 +++++++++++++------ snapshot/minidump/module_snapshot_minidump.h | 3 + .../process_snapshot_minidump_test.cc | 75 ++++++++++++++++- 3 files changed, 134 insertions(+), 24 deletions(-) diff --git a/snapshot/minidump/module_snapshot_minidump.cc b/snapshot/minidump/module_snapshot_minidump.cc index 06cd1bb6..b3e33d04 100644 --- a/snapshot/minidump/module_snapshot_minidump.cc +++ b/snapshot/minidump/module_snapshot_minidump.cc @@ -14,10 +14,14 @@ #include "snapshot/minidump/module_snapshot_minidump.h" +#include <string.h> + #include "minidump/minidump_extensions.h" #include "snapshot/minidump/minidump_annotation_reader.h" +#include "snapshot/minidump/minidump_string_reader.h" #include "snapshot/minidump/minidump_simple_string_dictionary_reader.h" #include "snapshot/minidump/minidump_string_list_reader.h" +#include "util/misc/pdb_structures.h" namespace crashpad { namespace internal { @@ -27,6 +31,10 @@ ModuleSnapshotMinidump::ModuleSnapshotMinidump() minidump_module_(), annotations_vector_(), annotations_simple_map_(), + annotation_objects_(), + uuid_(), + name_(), + age_(0), initialized_() { } @@ -53,32 +61,52 @@ bool ModuleSnapshotMinidump::Initialize( return false; } + ReadMinidumpUTF16String(file_reader, minidump_module_.ModuleNameRva, &name_); + + if (minidump_module_.CvRecord.Rva != 0) { + CodeViewRecordPDB70 cv; + + if (!file_reader->SeekSet(minidump_module_.CvRecord.Rva)) { + return false; + } + + if (!file_reader->ReadExactly(&cv, sizeof(cv))) { + return false; + } + + if (cv.signature == 'SDSR') { + age_ = cv.age; + uuid_ = cv.uuid; + } else if (cv.signature != '01BN') { + LOG(ERROR) << "Bad CodeView signature in module"; + return false; + } else { + LOG(ERROR) << "NB10 not supported"; + return false; + } + } + INITIALIZATION_STATE_SET_VALID(initialized_); return true; } std::string ModuleSnapshotMinidump::Name() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return std::string(); + return name_; } uint64_t ModuleSnapshotMinidump::Address() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return 0; + return minidump_module_.BaseOfImage; } uint64_t ModuleSnapshotMinidump::Size() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return 0; + return minidump_module_.SizeOfImage; } time_t ModuleSnapshotMinidump::Timestamp() const { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return 0; + return minidump_module_.TimeDateStamp; } void ModuleSnapshotMinidump::FileVersion(uint16_t* version_0, @@ -86,11 +114,12 @@ void ModuleSnapshotMinidump::FileVersion(uint16_t* version_0, uint16_t* version_2, uint16_t* version_3) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - *version_0 = 0; - *version_1 = 0; - *version_2 = 0; - *version_3 = 0; + uint32_t version_01 = minidump_module_.VersionInfo.dwFileVersionMS; + uint32_t version_23 = minidump_module_.VersionInfo.dwFileVersionLS; + *version_0 = static_cast<uint16_t>(version_01 >> 16); + *version_1 = static_cast<uint16_t>(version_01 & 0xFFFF); + *version_2 = static_cast<uint16_t>(version_23 >> 16); + *version_3 = static_cast<uint16_t>(version_23 & 0xFFFF); } void ModuleSnapshotMinidump::SourceVersion(uint16_t* version_0, @@ -98,25 +127,30 @@ void ModuleSnapshotMinidump::SourceVersion(uint16_t* version_0, uint16_t* version_2, uint16_t* version_3) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - *version_0 = 0; - *version_1 = 0; - *version_2 = 0; - *version_3 = 0; + uint32_t version_01 = minidump_module_.VersionInfo.dwProductVersionMS; + uint32_t version_23 = minidump_module_.VersionInfo.dwProductVersionLS; + *version_0 = static_cast<uint16_t>(version_01 >> 16); + *version_1 = static_cast<uint16_t>(version_01 & 0xFFFF); + *version_2 = static_cast<uint16_t>(version_23 >> 16); + *version_3 = static_cast<uint16_t>(version_23 & 0xFFFF); } ModuleSnapshot::ModuleType ModuleSnapshotMinidump::GetModuleType() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 + switch (minidump_module_.VersionInfo.dwFileType) { + case VFT_APP: + return kModuleTypeExecutable; + case VFT_DLL: + return kModuleTypeSharedLibrary; + } return kModuleTypeUnknown; } void ModuleSnapshotMinidump::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - *uuid = crashpad::UUID(); - *age = 0; + *uuid = uuid_; + *age = age_; } std::string ModuleSnapshotMinidump::DebugFileName() const { diff --git a/snapshot/minidump/module_snapshot_minidump.h b/snapshot/minidump/module_snapshot_minidump.h index e9dfa778..e6e50c51 100644 --- a/snapshot/minidump/module_snapshot_minidump.h +++ b/snapshot/minidump/module_snapshot_minidump.h @@ -92,6 +92,9 @@ class ModuleSnapshotMinidump final : public ModuleSnapshot { std::vector<std::string> annotations_vector_; std::map<std::string, std::string> annotations_simple_map_; std::vector<AnnotationSnapshot> annotation_objects_; + UUID uuid_; + std::string name_; + uint32_t age_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ModuleSnapshotMinidump); diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index b710f028..876356c8 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -20,11 +20,13 @@ #include <memory> +#include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" #include "minidump/minidump_context.h" #include "snapshot/minidump/minidump_annotation_reader.h" #include "snapshot/module_snapshot.h" #include "util/file/string_file.h" +#include "util/misc/pdb_structures.h" namespace crashpad { namespace test { @@ -288,7 +290,42 @@ TEST(ProcessSnapshotMinidump, Modules) { EXPECT_TRUE(string_file.Write(&header, sizeof(header))); MINIDUMP_MODULE minidump_module = {}; - uint32_t minidump_module_count = 4; + constexpr uint32_t minidump_module_count = 4; + RVA name_rvas[minidump_module_count]; + std::string names[minidump_module_count] = { + "libtacotruck", + "libevidencebased", + "libgeorgism", + "librealistutopia", + }; + + minidump_module.BaseOfImage = 0xbadf00d; + minidump_module.SizeOfImage = 9001; + minidump_module.TimeDateStamp = 1970; + minidump_module.VersionInfo.dwFileVersionMS = 0xAABBCCDD; + minidump_module.VersionInfo.dwFileVersionLS = 0xEEFF4242; + minidump_module.VersionInfo.dwProductVersionMS = 0xAAAABBBB; + minidump_module.VersionInfo.dwProductVersionLS = 0xCCCCDDDD; + minidump_module.VersionInfo.dwFileType = VFT_APP; + + for (uint32_t i = 0; i < minidump_module_count; i++) { + name_rvas[i] = static_cast<RVA>(string_file.SeekGet()); + auto name16 = base::UTF8ToUTF16(names[i]); + uint32_t size = sizeof(name16[0]) * name16.size(); + EXPECT_TRUE(string_file.Write(&size, sizeof(size))); + EXPECT_TRUE(string_file.Write(&name16[0], size)); + } + + CodeViewRecordPDB70 cv; + cv.signature = CodeViewRecordPDB70::kSignature; + cv.age = 7; + cv.uuid.InitializeFromString("00112233-4455-6677-8899-aabbccddeeff"); + cv.pdb_name[0] = '\0'; + + minidump_module.CvRecord.Rva = static_cast<RVA>(string_file.SeekGet()); + minidump_module.CvRecord.DataSize = sizeof(cv); + + EXPECT_TRUE(string_file.Write(&cv, sizeof(cv))); MINIDUMP_DIRECTORY minidump_module_list_directory = {}; minidump_module_list_directory.StreamType = kMinidumpStreamTypeModuleList; @@ -303,7 +340,9 @@ TEST(ProcessSnapshotMinidump, Modules) { for (uint32_t minidump_module_index = 0; minidump_module_index < minidump_module_count; ++minidump_module_index) { + minidump_module.ModuleNameRva = name_rvas[minidump_module_index]; EXPECT_TRUE(string_file.Write(&minidump_module, sizeof(minidump_module))); + minidump_module.TimeDateStamp++; } MinidumpModuleCrashpadInfo crashpad_module_0 = {}; @@ -399,6 +438,40 @@ TEST(ProcessSnapshotMinidump, Modules) { std::vector<const ModuleSnapshot*> modules = process_snapshot.Modules(); ASSERT_EQ(modules.size(), minidump_module_count); + for (uint32_t i = 0; i < minidump_module_count; i++) { + EXPECT_EQ(modules[i]->Name(), names[i]); + EXPECT_EQ(modules[i]->Address(), 0xbadf00dU); + EXPECT_EQ(modules[i]->Size(), 9001U); + EXPECT_EQ(modules[i]->Timestamp(), 1970U + i); + + uint16_t v0; + uint16_t v1; + uint16_t v2; + uint16_t v3; + + modules[i]->FileVersion(&v0, &v1, &v2, &v3); + EXPECT_EQ(v0, 0xAABBU); + EXPECT_EQ(v1, 0xCCDDU); + EXPECT_EQ(v2, 0xEEFFU); + EXPECT_EQ(v3, 0x4242U); + + modules[i]->SourceVersion(&v0, &v1, &v2, &v3); + EXPECT_EQ(v0, 0xAAAAU); + EXPECT_EQ(v1, 0xBBBBU); + EXPECT_EQ(v2, 0xCCCCU); + EXPECT_EQ(v3, 0xDDDDU); + + EXPECT_EQ(modules[i]->GetModuleType(), + ModuleSnapshot::kModuleTypeExecutable); + + uint32_t age; + UUID uuid; + modules[i]->UUIDAndAge(&uuid, &age); + + EXPECT_EQ(uuid.ToString(), "00112233-4455-6677-8899-aabbccddeeff"); + EXPECT_EQ(age, 7U); + } + auto annotations_simple_map = modules[0]->AnnotationsSimpleMap(); EXPECT_EQ(annotations_simple_map, dictionary_0); From 2dee96b841147d92c9a15a857013c8ec883d2aab Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 19 Oct 2018 09:11:07 -0700 Subject: [PATCH 051/401] Remove use of MSVC_SUPPRESS_WARNING Upstreaming of https://chromium-review.googlesource.com/c/chromium/src/+/1290574. Change-Id: I4e37879f34b6db7ee93b04b999bbae1ac4d645ae Reviewed-on: https://chromium-review.googlesource.com/c/1291054 Reviewed-by: Scott Graham <scottmg@chromium.org> --- minidump/minidump_file_writer_test.cc | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index 730da26b..067ef96b 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -20,7 +20,7 @@ #include <string> #include <utility> -#include "base/compiler_specific.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "minidump/minidump_stream_writer.h" #include "minidump/minidump_user_extension_stream_data_source.h" @@ -392,21 +392,16 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) { } TEST(MinidumpFileWriter, InitializeFromSnapshot_Exception) { - // In a 32-bit environment, this will give a “timestamp out of range” warning, + // In a 32-bit environment, this will give a “timestamp out of range” warning, // but the test should complete without failure. constexpr uint32_t kSnapshotTime = 0xfd469ab8; -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconstant-conversion" -#define DISABLED_WCONSTANT_CONVERSION -#endif // __clang__ - MSVC_SUPPRESS_WARNING(4309); // Truncation of constant value. - MSVC_SUPPRESS_WARNING(4838); // Narrowing conversion. - constexpr timeval kSnapshotTimeval = {static_cast<time_t>(kSnapshotTime), 0}; -#if defined(DISABLED_WCONSTANT_CONVERSION) -#pragma clang diagnostic pop -#undef DISABLED_WCONSTANT_CONVERSION -#endif // DISABLED_WCONSTANT_CONVERSION + constexpr timeval kSnapshotTimeval = { +#ifdef OS_WIN + static_cast<long>(kSnapshotTime), +#else + static_cast<time_t>(kSnapshotTime), +#endif + 0}; TestProcessSnapshot process_snapshot; process_snapshot.SetSnapshotTime(kSnapshotTimeval); From bf327d8ceb6a669607b0dbab5a83a275d03f99ed Mon Sep 17 00:00:00 2001 From: Vyacheslav Egorov <vegorov@chromium.org> Date: Mon, 22 Oct 2018 19:10:29 +0200 Subject: [PATCH 052/401] Introduce "dart" dependencies configuration for embedding into Dart VM. This configuration has the following dependencies layout: * gtest should be pulled from //third_party/googletest * zlib from //third_party/zlib * base from //third_party/mini_chromium/mini_chromium/base * Windows build configs come from //build/config/win:*. Bug: crashpad: Change-Id: I22b44d4f85349383063bf3785a321e3c23d88853 Reviewed-on: https://chromium-review.googlesource.com/c/1291378 Commit-Queue: Vyacheslav Egorov <vegorov@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- build/crashpad_buildconfig.gni | 14 ++++++-------- handler/BUILD.gn | 2 +- third_party/gtest/BUILD.gn | 2 +- third_party/mini_chromium/BUILD.gn | 4 ++++ third_party/zlib/BUILD.gn | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/build/crashpad_buildconfig.gni b/build/crashpad_buildconfig.gni index bef534a2..7db56d60 100644 --- a/build/crashpad_buildconfig.gni +++ b/build/crashpad_buildconfig.gni @@ -15,14 +15,10 @@ declare_args() { # Determines various flavors of build configuration, and which concrete # targets to use for dependencies. Valid values are "standalone", "chromium", - # and "fuchsia". + # "fuchsia", "dart" or "external". crashpad_dependencies = "standalone" if (defined(is_fuchsia_tree) && is_fuchsia_tree) { - # Determines various flavors of build configuration, and which concrete - # targets to use for dependencies. Valid values are "standalone", - # "chromium", and "fuchsia". Defaulted to "fuchsia" because - # "is_fuchsia_tree" is set. crashpad_dependencies = "fuchsia" } } @@ -30,10 +26,12 @@ declare_args() { assert(crashpad_dependencies == "chromium" || crashpad_dependencies == "fuchsia" || crashpad_dependencies == "standalone" || - crashpad_dependencies == "external") + crashpad_dependencies == "external" || + crashpad_dependencies == "dart") crashpad_is_in_chromium = crashpad_dependencies == "chromium" crashpad_is_in_fuchsia = crashpad_dependencies == "fuchsia" +crashpad_is_in_dart = crashpad_dependencies == "dart" crashpad_is_external = crashpad_dependencies == "external" crashpad_is_standalone = crashpad_dependencies == "standalone" @@ -48,8 +46,8 @@ if (crashpad_is_in_chromium) { crashpad_is_clang = is_clang } else { - # External builds assume crashpad and mini_chromium are peers. - if (crashpad_is_external) { + # External and Dart SDK builds assume crashpad and mini_chromium are peers. + if (crashpad_is_external || crashpad_is_in_dart) { import("../../../mini_chromium/mini_chromium/build/compiler.gni") import("../../../mini_chromium/mini_chromium/build/platform.gni") } else { diff --git a/handler/BUILD.gn b/handler/BUILD.gn index a1fe65da..ea33260c 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -154,7 +154,7 @@ crashpad_executable("crashpad_handler") { } if (crashpad_is_win) { - if (crashpad_is_in_chromium) { + if (crashpad_is_in_chromium || crashpad_is_in_dart) { remove_configs = [ "//build/config/win:console" ] configs = [ "//build/config/win:windowed" ] } else { diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index db5f4a56..fbad4d1a 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -28,7 +28,7 @@ if (crashpad_is_in_chromium) { "//testing/gmock", ] } -} else if (crashpad_is_in_fuchsia) { +} else if (crashpad_is_in_dart || crashpad_is_in_fuchsia) { group("gtest") { testonly = true public_deps = [ diff --git a/third_party/mini_chromium/BUILD.gn b/third_party/mini_chromium/BUILD.gn index e11d0111..095267ff 100644 --- a/third_party/mini_chromium/BUILD.gn +++ b/third_party/mini_chromium/BUILD.gn @@ -23,6 +23,10 @@ group("base") { public_deps = [ "mini_chromium/base", ] + } else if (crashpad_is_in_dart) { + public_deps = [ + "//third_party/mini_chromium/mini_chromium/base" + ] } } diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn index 0723ba3e..c436bc87 100644 --- a/third_party/zlib/BUILD.gn +++ b/third_party/zlib/BUILD.gn @@ -14,7 +14,7 @@ import("../../build/crashpad_buildconfig.gni") -if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { +if (crashpad_is_in_chromium || crashpad_is_in_fuchsia || crashpad_is_in_dart) { zlib_source = "external" } else if (!crashpad_is_win && !crashpad_is_fuchsia) { zlib_source = "system" From 411f0ae41d96518dfa9b75f58424d5d26eb7c75c Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Mon, 22 Oct 2018 11:14:09 -0700 Subject: [PATCH 053/401] Implement MemoryMap for ProcessSnapshotMinidump Bug: crashpad:10 Change-Id: Icca05321b729fd869a371707940fab40e12e8e22 Reviewed-on: https://chromium-review.googlesource.com/c/1294254 Commit-Queue: Casey Dahlin <sadmac@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- .../minidump/process_snapshot_minidump.cc | 72 ++++++++++++++++++- snapshot/minidump/process_snapshot_minidump.h | 11 +++ .../process_snapshot_minidump_test.cc | 71 ++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index a9bd0f04..12738434 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -16,11 +16,29 @@ #include <utility> +#include "snapshot/memory_map_region_snapshot.h" #include "snapshot/minidump/minidump_simple_string_dictionary_reader.h" #include "util/file/file_io.h" namespace crashpad { +namespace internal { + +class MemoryMapRegionSnapshotMinidump : public MemoryMapRegionSnapshot { + public: + MemoryMapRegionSnapshotMinidump(MINIDUMP_MEMORY_INFO info) : info_(info) {} + ~MemoryMapRegionSnapshotMinidump() override = default; + + const MINIDUMP_MEMORY_INFO& AsMinidumpMemoryInfo() const override { + return info_; + } + + private: + MINIDUMP_MEMORY_INFO info_; +}; + +} // namespace internal + ProcessSnapshotMinidump::ProcessSnapshotMinidump() : ProcessSnapshot(), header_(), @@ -90,6 +108,7 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { !InitializeMiscInfo() || !InitializeModules() || !InitializeSystemSnapshot() || + !InitializeMemoryInfo() || !InitializeThreads()) { return false; } @@ -194,8 +213,7 @@ const ExceptionSnapshot* ProcessSnapshotMinidump::Exception() const { std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotMinidump::MemoryMap() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return std::vector<const MemoryMapRegionSnapshot*>(); + return mem_regions_exposed_; } std::vector<HandleSnapshot> ProcessSnapshotMinidump::Handles() const { @@ -396,6 +414,56 @@ bool ProcessSnapshotMinidump::InitializeModulesCrashpadInfo( return true; } +bool ProcessSnapshotMinidump::InitializeMemoryInfo() { + const auto& stream_it = stream_map_.find(kMinidumpStreamTypeMemoryInfoList); + if (stream_it == stream_map_.end()) { + return true; + } + + if (stream_it->second->DataSize < sizeof(MINIDUMP_MEMORY_INFO_LIST)) { + LOG(ERROR) << "memory_info_list size mismatch"; + return false; + } + + if (!file_reader_->SeekSet(stream_it->second->Rva)) { + return false; + } + + MINIDUMP_MEMORY_INFO_LIST list; + + if (!file_reader_->ReadExactly(&list, sizeof(list))) { + return false; + } + + if (list.SizeOfHeader != sizeof(list)) { + return false; + } + + if (list.SizeOfEntry != sizeof(MINIDUMP_MEMORY_INFO)) { + return false; + } + + if (sizeof(MINIDUMP_MEMORY_INFO_LIST) + + list.NumberOfEntries * list.SizeOfEntry != stream_it->second->DataSize) { + LOG(ERROR) << "memory_info_list size mismatch"; + return false; + } + + for (uint32_t i = 0; i < list.NumberOfEntries; i++) { + MINIDUMP_MEMORY_INFO info; + + if (!file_reader_->ReadExactly(&info, sizeof(info))) { + return false; + } + + mem_regions_.emplace_back( + std::make_unique<internal::MemoryMapRegionSnapshotMinidump>(info)); + mem_regions_exposed_.emplace_back(mem_regions_.back().get()); + } + + return true; +} + bool ProcessSnapshotMinidump::InitializeThreads() { const auto& stream_it = stream_map_.find(kMinidumpStreamTypeThreadList); if (stream_it == stream_map_.end()) { diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 2ef23a68..3f256184 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -43,6 +43,10 @@ namespace crashpad { +namespace internal { +class MemoryMapRegionSnapshotMinidump; +} // namespace internal + //! \brief A ProcessSnapshot based on a minidump file. class ProcessSnapshotMinidump final : public ProcessSnapshot { public: @@ -91,6 +95,10 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { // Initialize(). bool InitializeThreads(); + // Initializes data carried in a MINIDUMP_MEMORY_INFO_LIST stream on behalf of + // Initialize(). + bool InitializeMemoryInfo(); + // Initializes data carried in a MINIDUMP_SYSTEM_INFO stream on behalf of // Initialize(). bool InitializeSystemSnapshot(); @@ -112,6 +120,9 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector<std::unique_ptr<internal::ModuleSnapshotMinidump>> modules_; std::vector<std::unique_ptr<internal::ThreadSnapshotMinidump>> threads_; std::vector<UnloadedModuleSnapshot> unloaded_modules_; + std::vector<std::unique_ptr<internal::MemoryMapRegionSnapshotMinidump>> + mem_regions_; + std::vector<const MemoryMapRegionSnapshot*> mem_regions_exposed_; MinidumpCrashpadInfo crashpad_info_; internal::SystemSnapshotMinidump system_snapshot_; CPUArchitecture arch_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 876356c8..ceae1c72 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -24,6 +24,7 @@ #include "gtest/gtest.h" #include "minidump/minidump_context.h" #include "snapshot/minidump/minidump_annotation_reader.h" +#include "snapshot/memory_map_region_snapshot.h" #include "snapshot/module_snapshot.h" #include "util/file/string_file.h" #include "util/misc/pdb_structures.h" @@ -968,6 +969,76 @@ TEST(ProcessSnapshotMinidump, ThreadContextX86_64) { } } +TEST(ProcessSnapshotMinidump, MemoryMap) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + MINIDUMP_MEMORY_INFO minidump_memory_info_1 = {}; + MINIDUMP_MEMORY_INFO minidump_memory_info_2 = {}; + uint32_t minidump_memory_info_count = 2; + + minidump_memory_info_1.BaseAddress = 1; + minidump_memory_info_1.AllocationBase = 2; + minidump_memory_info_1.AllocationProtect = 3; + minidump_memory_info_1.RegionSize = 4; + minidump_memory_info_1.State = 5; + minidump_memory_info_1.Protect = 6; + minidump_memory_info_1.Type = 6; + + minidump_memory_info_2.BaseAddress = 7; + minidump_memory_info_2.AllocationBase = 8; + minidump_memory_info_2.AllocationProtect = 9; + minidump_memory_info_2.RegionSize = 10; + minidump_memory_info_2.State = 11; + minidump_memory_info_2.Protect = 12; + minidump_memory_info_2.Type = 13; + + MINIDUMP_MEMORY_INFO_LIST minidump_memory_info_list = {}; + + minidump_memory_info_list.SizeOfHeader = sizeof(minidump_memory_info_list); + minidump_memory_info_list.SizeOfEntry = sizeof(MINIDUMP_MEMORY_INFO); + minidump_memory_info_list.NumberOfEntries = minidump_memory_info_count; + + MINIDUMP_DIRECTORY minidump_memory_info_list_directory = {}; + minidump_memory_info_list_directory.StreamType = + kMinidumpStreamTypeMemoryInfoList; + minidump_memory_info_list_directory.Location.DataSize = + sizeof(minidump_memory_info_list) + + minidump_memory_info_count * sizeof(MINIDUMP_MEMORY_INFO); + minidump_memory_info_list_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + EXPECT_TRUE(string_file.Write(&minidump_memory_info_list, + sizeof(minidump_memory_info_list))); + EXPECT_TRUE(string_file.Write(&minidump_memory_info_1, + sizeof(minidump_memory_info_1))); + EXPECT_TRUE(string_file.Write(&minidump_memory_info_2, + sizeof(minidump_memory_info_2))); + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + EXPECT_TRUE(string_file.Write(&minidump_memory_info_list_directory, + sizeof(minidump_memory_info_list_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + 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<const MemoryMapRegionSnapshot*> map = + process_snapshot.MemoryMap(); + ASSERT_EQ(map.size(), minidump_memory_info_count); + EXPECT_EQ(memcmp(&map[0]->AsMinidumpMemoryInfo(), &minidump_memory_info_1, + sizeof(minidump_memory_info_1)), 0); + EXPECT_EQ(memcmp(&map[1]->AsMinidumpMemoryInfo(), &minidump_memory_info_2, + sizeof(minidump_memory_info_2)), 0); +} + } // namespace } // namespace test } // namespace crashpad From df5d1aa3ff29b91c229fcd3c6536485b2241bf9c Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Wed, 24 Oct 2018 13:22:00 -0700 Subject: [PATCH 054/401] Implement Stack() for ThreadSnapshotMinidump We also remove the NOTREACHED guard from ExtraMemory and just let it return nothing (see comment for rationale). This should be the last of the methods in ThreadSnapshotMinidump. Bug: crashpad:10 Change-Id: If7148d3ead1ae5887da300131efc8a078b350b54 Reviewed-on: https://chromium-review.googlesource.com/c/1296806 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Casey Dahlin <sadmac@google.com> --- snapshot/BUILD.gn | 2 + snapshot/minidump/memory_snapshot_minidump.cc | 108 ++++++++++++++++++ snapshot/minidump/memory_snapshot_minidump.h | 62 ++++++++++ .../process_snapshot_minidump_test.cc | 67 +++++++++++ snapshot/minidump/thread_snapshot_minidump.cc | 18 ++- snapshot/minidump/thread_snapshot_minidump.h | 4 +- snapshot/snapshot.gyp | 2 + 7 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 snapshot/minidump/memory_snapshot_minidump.cc create mode 100644 snapshot/minidump/memory_snapshot_minidump.h diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 768697db..3e75817d 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -44,6 +44,8 @@ static_library("snapshot") { "minidump/minidump_string_list_reader.h", "minidump/minidump_string_reader.cc", "minidump/minidump_string_reader.h", + "minidump/memory_snapshot_minidump.cc", + "minidump/memory_snapshot_minidump.h", "minidump/module_snapshot_minidump.cc", "minidump/module_snapshot_minidump.h", "minidump/process_snapshot_minidump.cc", diff --git a/snapshot/minidump/memory_snapshot_minidump.cc b/snapshot/minidump/memory_snapshot_minidump.cc new file mode 100644 index 00000000..37f54a2d --- /dev/null +++ b/snapshot/minidump/memory_snapshot_minidump.cc @@ -0,0 +1,108 @@ +// Copyright 2018 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/minidump/memory_snapshot_minidump.h" + +#include <memory> + +namespace crashpad { +namespace internal { + +MemorySnapshotMinidump::MemorySnapshotMinidump() + : MemorySnapshot(), + address_(0), + data_(), + initialized_() {} + +MemorySnapshotMinidump::~MemorySnapshotMinidump() {} + +bool MemorySnapshotMinidump::Initialize(FileReaderInterface* file_reader, + RVA location) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + MINIDUMP_MEMORY_DESCRIPTOR descriptor; + + if (!file_reader->SeekSet(location)) { + return false; + } + + if (!file_reader->ReadExactly(&descriptor, sizeof(descriptor))) { + return false; + } + + address_ = descriptor.StartOfMemoryRange; + data_.resize(descriptor.Memory.DataSize); + + if (!file_reader->SeekSet(descriptor.Memory.Rva)) { + return false; + } + + if (!file_reader->ReadExactly(data_.data(), data_.size())) { + return false; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +uint64_t MemorySnapshotMinidump::Address() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return address_; +} + +size_t MemorySnapshotMinidump::Size() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return data_.size(); +} + +bool MemorySnapshotMinidump::Read(Delegate* delegate) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return delegate->MemorySnapshotDelegateRead( + const_cast<uint8_t*>(data_.data()), data_.size()); +} + +const MemorySnapshot* MemorySnapshotMinidump::MergeWithOtherSnapshot( + const MemorySnapshot* other) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + // TODO: Verify type of other + auto other_cast = reinterpret_cast<const MemorySnapshotMinidump*>(other); + + INITIALIZATION_STATE_DCHECK_VALID(other_cast->initialized_); + + if (other_cast->address_ < address_) { + return other_cast->MergeWithOtherSnapshot(this); + } + + CheckedRange<uint64_t, size_t> merged(0, 0); + if (!LoggingDetermineMergedRange(this, other, &merged)) { + return nullptr; + } + + auto result = std::make_unique<MemorySnapshotMinidump>(); + result->address_ = merged.base(); + result->data_ = data_; + + if (result->data_.size() == merged.size()) { + return result.release(); + } + + result->data_.resize(other_cast->address_ - address_); + result->data_.insert(result->data_.end(), other_cast->data_.begin(), + other_cast->data_.end()); + return result.release(); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/minidump/memory_snapshot_minidump.h b/snapshot/minidump/memory_snapshot_minidump.h new file mode 100644 index 00000000..f0b83c57 --- /dev/null +++ b/snapshot/minidump/memory_snapshot_minidump.h @@ -0,0 +1,62 @@ +// Copyright 2018 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_MINIDUMP_MEMORY_SNAPSHOT_MINIDUMP_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_MEMORY_SNAPSHOT_MINIDUMP_H_ + +#include <dbghelp.h> + +#include <vector> + +#include "base/macros.h" +#include "snapshot/memory_snapshot.h" +#include "util/file/file_reader.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { +class MemorySnapshotMinidump : public MemorySnapshot { + public: + MemorySnapshotMinidump(); + ~MemorySnapshotMinidump() override; + + //! \brief Initializes the object. + //! + //! \param[in] file_reader A file reader corresponding to a minidump file. + //! The file reader must support seeking. + //! \param[in] location The location within the file where we will find a + //! MINIDUMP_MEMORY_DESCRIPTOR from which to initialize this object. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! an appropriate message logged. + bool Initialize(FileReaderInterface* file_reader, RVA location); + + uint64_t Address() const override; + size_t Size() const override; + bool Read(Delegate* delegate) const override; + const MemorySnapshot* MergeWithOtherSnapshot( + const MemorySnapshot* other) const override; + + private: + uint64_t address_; + std::vector<uint8_t> data_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(MemorySnapshotMinidump); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_MEMORY_SNAPSHOT_MINIDUMP_H_ diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index ceae1c72..79b81859 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -33,6 +33,17 @@ namespace crashpad { namespace test { namespace { +class ReadToVector : public crashpad::MemorySnapshot::Delegate { + public: + std::vector<uint8_t> result; + + bool MemorySnapshotDelegateRead(void* data, size_t size) override { + result.resize(size); + memcpy(result.data(), data, size); + return true; + } +}; + TEST(ProcessSnapshotMinidump, EmptyFile) { StringFile string_file; ProcessSnapshotMinidump process_snapshot; @@ -1039,6 +1050,62 @@ TEST(ProcessSnapshotMinidump, MemoryMap) { sizeof(minidump_memory_info_2)), 0); } +TEST(ProcessSnapshotMinidump, Stacks) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + MINIDUMP_THREAD minidump_thread = {}; + uint32_t minidump_thread_count = 1; + + minidump_thread.ThreadId = 42; + minidump_thread.Stack.StartOfMemoryRange = 0xbeefd00d; + + std::vector<uint8_t> minidump_stack = { + '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + minidump_thread.Stack.Memory.DataSize = minidump_stack.size(); + minidump_thread.Stack.Memory.Rva = static_cast<RVA>(string_file.SeekGet()); + + EXPECT_TRUE(string_file.Write(minidump_stack.data(), minidump_stack.size())); + + MINIDUMP_DIRECTORY minidump_thread_list_directory = {}; + minidump_thread_list_directory.StreamType = kMinidumpStreamTypeThreadList; + minidump_thread_list_directory.Location.DataSize = + sizeof(MINIDUMP_THREAD_LIST) + + minidump_thread_count * sizeof(MINIDUMP_THREAD); + minidump_thread_list_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + // Fields in MINIDUMP_THREAD_LIST. + EXPECT_TRUE( + string_file.Write(&minidump_thread_count, sizeof(minidump_thread_count))); + EXPECT_TRUE(string_file.Write(&minidump_thread, sizeof(minidump_thread))); + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&minidump_thread_list_directory, + sizeof(minidump_thread_list_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + 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<const ThreadSnapshot*> threads = process_snapshot.Threads(); + ASSERT_EQ(threads.size(), minidump_thread_count); + + ReadToVector delegate; + threads[0]->Stack()->Read(&delegate); + + EXPECT_EQ(delegate.result, minidump_stack); +} + } // namespace } // namespace test } // namespace crashpad diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc index 458586d3..ddc15cf1 100644 --- a/snapshot/minidump/thread_snapshot_minidump.cc +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -14,6 +14,7 @@ #include "snapshot/minidump/thread_snapshot_minidump.h" +#include <stddef.h> #include <string.h> #include "minidump/minidump_context.h" @@ -24,6 +25,9 @@ namespace internal { ThreadSnapshotMinidump::ThreadSnapshotMinidump() : ThreadSnapshot(), minidump_thread_(), + context_(), + context_memory_(), + stack_(), initialized_() { } @@ -61,6 +65,13 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, return false; } + RVA stack_info_location = minidump_thread_rva + + offsetof(MINIDUMP_THREAD, Stack); + + if (!stack_.Initialize(file_reader, stack_info_location)) { + return false; + } + INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -337,13 +348,14 @@ const CPUContext* ThreadSnapshotMinidump::Context() const { const MemorySnapshot* ThreadSnapshotMinidump::Stack() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return nullptr; + return &stack_; } std::vector<const MemorySnapshot*> ThreadSnapshotMinidump::ExtraMemory() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 + // This doesn't correspond to anything minidump can give us, with the + // exception of the BackingStore field in the MINIDUMP_THREAD_EX structure, + // which is only valid for IA-64. return std::vector<const MemorySnapshot*>(); } diff --git a/snapshot/minidump/thread_snapshot_minidump.h b/snapshot/minidump/thread_snapshot_minidump.h index 338f2341..43234ddb 100644 --- a/snapshot/minidump/thread_snapshot_minidump.h +++ b/snapshot/minidump/thread_snapshot_minidump.h @@ -18,8 +18,9 @@ #include <windows.h> #include "minidump/minidump_extensions.h" -#include "snapshot/thread_snapshot.h" #include "snapshot/cpu_context.h" +#include "snapshot/minidump/memory_snapshot_minidump.h" +#include "snapshot/thread_snapshot.h" #include "util/file/file_reader.h" #include "util/misc/initialization_state_dcheck.h" @@ -66,6 +67,7 @@ class ThreadSnapshotMinidump : public ThreadSnapshot { MINIDUMP_THREAD minidump_thread_; CPUContext context_; std::vector<unsigned char> context_memory_; + MemorySnapshotMinidump stack_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ThreadSnapshotMinidump); diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 4c8a5cbf..dd60b0c1 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -115,6 +115,8 @@ 'minidump/minidump_string_list_reader.h', 'minidump/minidump_string_reader.cc', 'minidump/minidump_string_reader.h', + 'minidump/memory_snapshot_minidump.cc', + 'minidump/memory_snapshot_minidump.h', 'minidump/module_snapshot_minidump.cc', 'minidump/module_snapshot_minidump.h', 'minidump/process_snapshot_minidump.cc', From 8e329d12c791862ad3cd395b481831be3d62320d Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 19 Oct 2018 13:14:36 -0700 Subject: [PATCH 055/401] linux: Use capget syscall instead of its libc wrapper The sys/capability.h header is only present if libcap is installed. We were only using it for its declaration of a capget() wrapper. Using the system call directly allows compiling without installing libcap. Change-Id: I83dfc5c8d56bb3cdd4efb62e0c568d8a221334cd Reviewed-on: https://chromium-review.googlesource.com/c/1292231 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- handler/linux/exception_handler_server.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index 71a5dc74..12e73635 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -15,10 +15,11 @@ #include "handler/linux/exception_handler_server.h" #include <errno.h> -#include <sys/capability.h> +#include <linux/capability.h> #include <sys/epoll.h> #include <sys/eventfd.h> #include <sys/socket.h> +#include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> @@ -95,7 +96,7 @@ bool HaveCapSysPtrace() { cap_header.pid = getpid(); - if (capget(&cap_header, &cap_data) != 0) { + if (syscall(SYS_capget, &cap_header, &cap_data) != 0) { PLOG(ERROR) << "capget"; return false; } From 5dd094381ca3b5248c3a7994074d83db3b93872e Mon Sep 17 00:00:00 2001 From: Braden Kell <bradenkell@google.com> Date: Fri, 19 Oct 2018 16:10:56 -0700 Subject: [PATCH 056/401] [sysinfo] Convert sysinfo ioctls to FIDL calls Bug: fuchsia:ZX-2842 Change-Id: Ib84b4319d3bb07a2c68bc2ff0d63e49fa65eb2b5 Reviewed-on: https://chromium-review.googlesource.com/c/1292237 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- third_party/fuchsia/BUILD.gn | 64 ++++++++++++++++++++++++++++++++-- third_party/fuchsia/runner.py | 17 +++++++++ util/fuchsia/koid_utilities.cc | 23 +++++++++--- 3 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 third_party/fuchsia/runner.py diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 6c2339b9..a1ee935e 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -17,21 +17,77 @@ import("../../build/crashpad_buildconfig.gni") if (crashpad_is_in_fuchsia) { group("zx") { public_deps = [ + "//zircon/public/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c", + "//zircon/public/lib/fdio", "//zircon/public/lib/zx", ] } } else if (crashpad_is_in_chromium) { group("zx") { public_deps = [ + "//third_party/fuchsia-sdk:fdio", "//third_party/fuchsia-sdk:zx", + "//third_party/fuchsia-sdk/sdk:sysinfo", ] } } else { - sdk_pkg_path = "sdk/linux-amd64/pkg" + sdk_path = "sdk/linux-amd64" + sdk_pkg_path = "$sdk_path/pkg" + sdk_fidl_path = "$sdk_path/fidl" config("zx_config") { visibility = [ ":zx" ] - include_dirs = [ "$sdk_pkg_path/zx/include" ] + include_dirs = [ + "$root_gen_dir/fidl/include", + "$sdk_pkg_path/fidl/include", + "$sdk_pkg_path/zx/include", + ] + } + + fidl_sources = [ + { + fidl = "$sdk_fidl_path/fuchsia.sysinfo/sysinfo.fidl" + header_stem = "fuchsia/sysinfo" + library_name = "fuchsia.sysinfo" + }, + ] + + fidl_gen_sources = [] + foreach(fidl_source, fidl_sources) { + fidl_stem = "$target_gen_dir/fidl/${fidl_source.library_name}" + c_header = "$root_gen_dir/fidl/include/${fidl_source.header_stem}/c/fidl.h" + c_client = "$fidl_stem/client.cc" + coding_tables = "$fidl_stem/tables.cc" + + fidl_gen_sources += [ + c_client, + coding_tables, + ] + + action(fidl_source.library_name) { + visibility = [ ":*" ] + + script = "runner.py" + + args = [ + rebase_path("$sdk_path/tools/fidlc", root_build_dir), + "--c-header", + rebase_path(c_header, root_build_dir), + "--c-client", + rebase_path(c_client, root_build_dir), + "--tables", + rebase_path(coding_tables, root_build_dir), + "--files", + ] + [ rebase_path(fidl_source.fidl, root_build_dir) ] + + inputs = [ fidl_source.fidl, "$sdk_path/tools/fidlc" ] + + outputs = [ + c_client, + c_header, + coding_tables, + ] + } } static_library("zx") { @@ -75,7 +131,9 @@ if (crashpad_is_in_fuchsia) { "$sdk_pkg_path/zx/timer.cpp", "$sdk_pkg_path/zx/vmar.cpp", "$sdk_pkg_path/zx/vmo.cpp", - ] + ] + fidl_gen_sources + + deps = [ ":fuchsia.sysinfo" ] public_configs = [ ":zx_config" ] } diff --git a/third_party/fuchsia/runner.py b/third_party/fuchsia/runner.py new file mode 100644 index 00000000..da4ec99a --- /dev/null +++ b/third_party/fuchsia/runner.py @@ -0,0 +1,17 @@ +# Copyright 2018 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 os +import sys +os.execv(sys.argv[1], sys.argv[1:]) diff --git a/util/fuchsia/koid_utilities.cc b/util/fuchsia/koid_utilities.cc index 65d3d94e..bb40a1c1 100644 --- a/util/fuchsia/koid_utilities.cc +++ b/util/fuchsia/koid_utilities.cc @@ -14,9 +14,11 @@ #include "util/fuchsia/koid_utilities.h" +#include <fuchsia/sysinfo/c/fidl.h> +#include <lib/fdio/util.h> +#include <lib/zx/channel.h> #include <lib/zx/job.h> #include <lib/zx/process.h> -#include <zircon/device/sysinfo.h> #include <vector> @@ -52,11 +54,22 @@ zx::job GetRootJob() { if (!sysinfo.is_valid()) return zx::job(); + zx::channel channel; + zx_status_t status = fdio_get_service_handle(sysinfo.release(), + channel.reset_and_get_address()); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "fdio_get_service_handle"; + return zx::job(); + } + zx::handle root_job; - size_t n = ioctl_sysinfo_get_root_job(sysinfo.get(), - root_job.reset_and_get_address()); - if (n != sizeof(zx_handle_t)) { - LOG(ERROR) << "unexpected root job size"; + zx_status_t fidl_status = fuchsia_sysinfo_DeviceGetRootJob( + channel.get(), &status, root_job.reset_and_get_address()); + if (fidl_status != ZX_OK) { + ZX_LOG(ERROR, fidl_status) << "fuchsia_sysinfo_DeviceGetRootJob"; + return zx::job(); + } else if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "fuchsia_sysinfo_DeviceGetRootJob"; return zx::job(); } return CastHandle<zx::job>(std::move(root_job)); From 96391cb80f4785e4863653f5102ec04713adf37a Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 30 Oct 2018 15:33:39 -0700 Subject: [PATCH 057/401] [fuchsia] early return in handler on disable Tested:CQ Change-Id: Ifd742a7bfb213e4286bad582c81963e2fb383551 Reviewed-on: https://chromium-review.googlesource.com/c/1309156 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- .../fuchsia/crash_report_exception_handler.cc | 134 +++++++++--------- 1 file changed, 68 insertions(+), 66 deletions(-) diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index bd76a88d..85d91582 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -109,85 +109,87 @@ bool CrashReportExceptionHandler::HandleExceptionHandles( CrashpadInfoClientOptions client_options; process_snapshot.GetCrashpadOptions(&client_options); - if (client_options.crashpad_handler_behavior != TriState::kDisabled) { - zx_exception_report_t report; - zx_status_t status = thread.get_info(ZX_INFO_THREAD_EXCEPTION_REPORT, - &report, - sizeof(report), - nullptr, - nullptr); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) - << "zx_object_get_info ZX_INFO_THREAD_EXCEPTION_REPORT"; - return false; - } + if (client_options.crashpad_handler_behavior == TriState::kDisabled) { + return true; + } - zx_koid_t thread_id = GetKoidForHandle(thread); - if (!process_snapshot.InitializeException(thread_id, report)) { - return false; - } + zx_exception_report_t report; + zx_status_t status = thread.get_info(ZX_INFO_THREAD_EXCEPTION_REPORT, + &report, + sizeof(report), + nullptr, + nullptr); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) + << "zx_object_get_info ZX_INFO_THREAD_EXCEPTION_REPORT"; + return false; + } - UUID client_id; - Settings* const settings = database_->GetSettings(); - if (settings) { - // If GetSettings() or GetClientID() fails, something else will log a - // message and client_id will be left at its default value, all zeroes, - // which is appropriate. - settings->GetClientID(&client_id); - } + zx_koid_t thread_id = GetKoidForHandle(thread); + if (!process_snapshot.InitializeException(thread_id, report)) { + return false; + } - process_snapshot.SetClientID(client_id); - process_snapshot.SetAnnotationsSimpleMap(*process_annotations_); + UUID client_id; + Settings* const settings = database_->GetSettings(); + if (settings) { + // If GetSettings() or GetClientID() fails, something else will log a + // message and client_id will be left at its default value, all zeroes, + // which is appropriate. + settings->GetClientID(&client_id); + } - std::unique_ptr<CrashReportDatabase::NewReport> new_report; - CrashReportDatabase::OperationStatus database_status = - database_->PrepareNewCrashReport(&new_report); - if (database_status != CrashReportDatabase::kNoError) { - return false; - } + process_snapshot.SetClientID(client_id); + process_snapshot.SetAnnotationsSimpleMap(*process_annotations_); - process_snapshot.SetReportID(new_report->ReportID()); + std::unique_ptr<CrashReportDatabase::NewReport> new_report; + CrashReportDatabase::OperationStatus database_status = + database_->PrepareNewCrashReport(&new_report); + if (database_status != CrashReportDatabase::kNoError) { + return false; + } - MinidumpFileWriter minidump; - minidump.InitializeFromSnapshot(&process_snapshot); - AddUserExtensionStreams( - user_stream_data_sources_, &process_snapshot, &minidump); + process_snapshot.SetReportID(new_report->ReportID()); - if (!minidump.WriteEverything(new_report->Writer())) { - return false; - } + MinidumpFileWriter minidump; + minidump.InitializeFromSnapshot(&process_snapshot); + AddUserExtensionStreams( + user_stream_data_sources_, &process_snapshot, &minidump); - 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()); + if (!minidump.WriteEverything(new_report->Writer())) { + 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); - if (database_status != CrashReportDatabase::kNoError) { - return false; - } - if (local_report_id != nullptr) { - *local_report_id = uuid; - } + UUID uuid; + database_status = + database_->FinishedWritingCrashReport(std::move(new_report), &uuid); + if (database_status != CrashReportDatabase::kNoError) { + return false; + } + if (local_report_id != nullptr) { + *local_report_id = uuid; + } - if (upload_thread_) { - upload_thread_->ReportPending(uuid); - } + if (upload_thread_) { + upload_thread_->ReportPending(uuid); } return true; From e00c42e63fadfb71eee7ac292b7b983c66cc70da Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 31 Oct 2018 09:49:04 -0700 Subject: [PATCH 058/401] linux: use offset of d_name to get size of dirents Dirents with short names can have a d_name that fits inside padding at the end of Dirent64. Change-Id: I18057dad01f5a7d4a063028ca9f61fbe89ae7fc0 Reviewed-on: https://chromium-review.googlesource.com/c/1310413 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/linux/ptrace_client.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/linux/ptrace_client.cc b/util/linux/ptrace_client.cc index aa3e0244..34fcbc3a 100644 --- a/util/linux/ptrace_client.cc +++ b/util/linux/ptrace_client.cc @@ -92,7 +92,7 @@ struct Dirent64 { void ReadDentsAsThreadIDs(char* buffer, size_t size, std::vector<pid_t>* threads) { - while (size > sizeof(Dirent64)) { + while (size > offsetof(Dirent64, d_name)) { auto dirent = reinterpret_cast<Dirent64*>(buffer); if (size < dirent->d_reclen) { LOG(ERROR) << "short dirent"; From 95e97a32eba4d505ab9591e683d2147c441eea48 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 30 Oct 2018 18:11:33 -0700 Subject: [PATCH 059/401] Use a relative address in .note.crashpad.info The desc value in the note is now the offset of CRASHPAD_INFO_SYMBOL from desc. Making this note writable can trigger a linker error resulting in the binary embedding .note.crashpad.info to be rejected by the kernel during program loading. The error was observed with: GNU ld (GNU Binutils for Debian) 2.30 clang version 4.0.1-10 (tags/RELEASE_401/final) Debian 4.17.17-1rodete2 When the note is made writable, crashpad_snapshot_test contains two PT_LOAD segments which map to the same page. LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000258 0x0000000000000258 R 0x200000 LOAD 0x0000000000000258 0x0000000000000258 0x0000000000000258 0x00000000002b84d8 0x00000000002b8950 RWE 0x200000 Executing this binary with the execv system call triggers a segfault during program loading (an error can't be returned because the original process vm has already been discarded). I suspect (I haven't set up a debuggable kernel) the failure occurs while attempting to map the second load segment because its virtual address, 0x258, is in the same page as the first load segment. https://elixir.bootlin.com/linux/v4.17.17/source/fs/binfmt_elf.c#L380 The linker normally produces consecutive load segments where the second segment is loaded 0x200000 bytes after the first, which I think is the maximum expected page size. Modifying the test executable to load the second segment at 0x1258 (4096 byte page size) allows program loading to succeed (but of course crashes after control is given to it). Bug: crashpad:260 Change-Id: I2b9f1e66e98919138baef3da991a9710bd970dc4 Reviewed-on: https://chromium-review.googlesource.com/c/1292232 Reviewed-by: Scott Graham <scottmg@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_info_note.S | 18 +++++++----------- snapshot/crashpad_info_size_test_note.S | 18 +++++++----------- snapshot/elf/elf_image_reader.cc | 12 ++++++++---- snapshot/elf/elf_image_reader.h | 16 ++++++++++++---- snapshot/elf/elf_image_reader_fuzzer.cc | 4 +++- snapshot/elf/elf_image_reader_test.cc | 10 ++++++---- snapshot/elf/module_snapshot_elf.cc | 15 ++++++++++++--- 7 files changed, 55 insertions(+), 38 deletions(-) diff --git a/client/crashpad_info_note.S b/client/crashpad_info_note.S index 4c29298d..b60093c9 100644 --- a/client/crashpad_info_note.S +++ b/client/crashpad_info_note.S @@ -26,9 +26,11 @@ #define NOTE_ALIGN 4 // This section must be "a"llocated so that it appears in the final binary at - // runtime, and "w"ritable so that the relocation to CRASHPAD_INFO_SYMBOL can - // be performed. - .section .note.crashpad.info,"aw",%note + // runtime. The reference to CRASHPAD_INFO_SYMBOL uses an offset relative to + // this note to avoid making this note writable, which triggers a bug in GNU + // ld, or adding text relocations which require the target system to allow + // making text segments writable. https://crbug.com/crashpad/260. + .section .note.crashpad.info,"a",%note .balign NOTE_ALIGN # .globl indicates that it's available to link against other .o files. .hidden # indicates that it will not appear in the executable's symbol table. @@ -45,15 +47,9 @@ name_end: .balign NOTE_ALIGN desc: #if defined(__LP64__) - .quad CRASHPAD_INFO_SYMBOL + .quad CRASHPAD_INFO_SYMBOL - desc #else -#if defined(__LITTLE_ENDIAN__) - .long CRASHPAD_INFO_SYMBOL - .long 0 -#else - .long 0 - .long CRASHPAD_INFO_SYMBOL -#endif // __LITTLE_ENDIAN__ + .long CRASHPAD_INFO_SYMBOL - desc #endif // __LP64__ desc_end: .size CRASHPAD_NOTE_REFERENCE, .-CRASHPAD_NOTE_REFERENCE diff --git a/snapshot/crashpad_info_size_test_note.S b/snapshot/crashpad_info_size_test_note.S index 96b996db..16b5d499 100644 --- a/snapshot/crashpad_info_size_test_note.S +++ b/snapshot/crashpad_info_size_test_note.S @@ -26,9 +26,11 @@ #define NOTE_ALIGN 4 // This section must be "a"llocated so that it appears in the final binary at - // runtime, and "w"ritable so that the relocation to TEST_CRASHPAD_INFO_SYMBOL - // can be performed. - .section .note.crashpad.info,"aw",%note + // runtime. The reference to TEST_CRASHPAD_INFO_SYMBOL uses an offset relative + // to this note to avoid making this note writable, which triggers a bug in + // GNU ld, or adding text relocations which require the target system to allow + // making text segments writable. https://crbug.com/crashpad/260. + .section .note.crashpad.info,"a",%note .balign NOTE_ALIGN .type info_size_test_note, %object info_size_test_note: @@ -41,15 +43,9 @@ name_end: .balign NOTE_ALIGN desc: #if defined(__LP64__) - .quad TEST_CRASHPAD_INFO_SYMBOL + .quad TEST_CRASHPAD_INFO_SYMBOL - desc #else -#if defined(__LITTLE_ENDIAN__) - .long TEST_CRASHPAD_INFO_SYMBOL - .long 0 -#else - .long 0 - .long TEST_CRASHPAD_INFO_SYMBOL -#endif // __LITTLE_ENDIAN__ + .long TEST_CRASHPAD_INFO_SYMBOL - desc #endif // __LP64__ desc_end: .size info_size_test_note, .-info_size_test_note diff --git a/snapshot/elf/elf_image_reader.cc b/snapshot/elf/elf_image_reader.cc index 8ee51d34..ffe3f7b1 100644 --- a/snapshot/elf/elf_image_reader.cc +++ b/snapshot/elf/elf_image_reader.cc @@ -191,7 +191,8 @@ ElfImageReader::NoteReader::~NoteReader() = default; ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::NextNote( std::string* name, NoteType* type, - std::string* desc) { + std::string* desc, + VMAddress* desc_address) { if (!is_valid_) { LOG(ERROR) << "invalid note reader"; return Result::kError; @@ -215,8 +216,9 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::NextNote( } retry_ = false; - result = range_->Is64Bit() ? ReadNote<Elf64_Nhdr>(name, type, desc) - : ReadNote<Elf32_Nhdr>(name, type, desc); + result = range_->Is64Bit() + ? ReadNote<Elf64_Nhdr>(name, type, desc, desc_address) + : ReadNote<Elf32_Nhdr>(name, type, desc, desc_address); } while (retry_); if (result == Result::kSuccess) { @@ -251,7 +253,8 @@ template <typename NhdrType> ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( std::string* name, NoteType* type, - std::string* desc) { + std::string* desc, + VMAddress* desc_address) { static_assert(sizeof(*type) >= sizeof(NhdrType::n_namesz), "Note field size mismatch"); DCHECK_LT(current_address_, segment_end_address_); @@ -317,6 +320,7 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( current_address_, note_info.n_descsz, &local_desc[0])) { return Result::kError; } + *desc_address = current_address_; current_address_ = end_of_note; diff --git a/snapshot/elf/elf_image_reader.h b/snapshot/elf/elf_image_reader.h index 317b35ad..f35c7616 100644 --- a/snapshot/elf/elf_image_reader.h +++ b/snapshot/elf/elf_image_reader.h @@ -70,9 +70,14 @@ class ElfImageReader { //! \param[out] name The name of the note owner, if not `nullptr`. //! \param[out] type A type for the note, if not `nullptr`. //! \param[out] desc The note descriptor. - //! \return a #Result value. \a name, \a type, and \a desc are only valid if - //! this method returns Result::kSuccess. - Result NextNote(std::string* name, NoteType* type, std::string* desc); + //! \param[out] desc_addr The address in the remote process' address space + //! \a desc was read from. + //! \return a #Result value. \a name, \a type, \a desc, and \a desc_addr are + //! only valid if this method returns Result::kSuccess. + Result NextNote(std::string* name, + NoteType* type, + std::string* desc, + VMAddress* desc_addr); // private NoteReader(const ElfImageReader* elf_reader_, @@ -88,7 +93,10 @@ class ElfImageReader { // and returns kError if use_filter_ is true and the note's name and type do // not match name_filter_ and type_filter_. template <typename T> - Result ReadNote(std::string* name, NoteType* type, std::string* desc); + Result ReadNote(std::string* name, + NoteType* type, + std::string* desc, + VMAddress* desc_addr); VMAddress current_address_; VMAddress segment_end_address_; diff --git a/snapshot/elf/elf_image_reader_fuzzer.cc b/snapshot/elf/elf_image_reader_fuzzer.cc index 1686650b..73bded72 100644 --- a/snapshot/elf/elf_image_reader_fuzzer.cc +++ b/snapshot/elf/elf_image_reader_fuzzer.cc @@ -65,8 +65,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { std::string note_name; std::string note_desc; ElfImageReader::NoteReader::NoteType note_type; + VMAddress desc_addr; auto notes = reader.Notes(-1); - while ((result = notes->NextNote(¬e_name, ¬e_type, ¬e_desc)) == + while ((result = notes->NextNote( + ¬e_name, ¬e_type, ¬e_desc, &desc_addr)) == ElfImageReader::NoteReader::Result::kSuccess) { LOG(ERROR) << note_name << note_type << note_desc; } diff --git a/snapshot/elf/elf_image_reader_test.cc b/snapshot/elf/elf_image_reader_test.cc index 6d88d817..2cc0faa5 100644 --- a/snapshot/elf/elf_image_reader_test.cc +++ b/snapshot/elf/elf_image_reader_test.cc @@ -154,22 +154,24 @@ void ReadThisExecutableInTarget(ProcessType process, std::string note_name; std::string note_desc; ElfImageReader::NoteReader::NoteType note_type; + VMAddress desc_addr; std::unique_ptr<ElfImageReader::NoteReader> notes = reader.Notes(-1); - while ((result = notes->NextNote(¬e_name, ¬e_type, ¬e_desc)) == + while ((result = notes->NextNote( + ¬e_name, ¬e_type, ¬e_desc, &desc_addr)) == ElfImageReader::NoteReader::Result::kSuccess) { } EXPECT_EQ(result, ElfImageReader::NoteReader::Result::kNoMoreNotes); notes = reader.Notes(0); - EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc), + EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), ElfImageReader::NoteReader::Result::kNoMoreNotes); // Find the note defined in elf_image_reader_test_note.S. constexpr uint32_t kCrashpadNoteDesc = 42; notes = reader.NotesWithNameAndType( CRASHPAD_ELF_NOTE_NAME, CRASHPAD_ELF_NOTE_TYPE_SNAPSHOT_TEST, -1); - ASSERT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc), + ASSERT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), ElfImageReader::NoteReader::Result::kSuccess); EXPECT_EQ(note_name, CRASHPAD_ELF_NOTE_NAME); EXPECT_EQ(note_type, @@ -178,7 +180,7 @@ void ReadThisExecutableInTarget(ProcessType process, EXPECT_EQ(*reinterpret_cast<decltype(kCrashpadNoteDesc)*>(¬e_desc[0]), kCrashpadNoteDesc); - EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc), + EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), ElfImageReader::NoteReader::Result::kNoMoreNotes); } diff --git a/snapshot/elf/module_snapshot_elf.cc b/snapshot/elf/module_snapshot_elf.cc index 62a961d3..39385a6d 100644 --- a/snapshot/elf/module_snapshot_elf.cc +++ b/snapshot/elf/module_snapshot_elf.cc @@ -56,9 +56,17 @@ bool ModuleSnapshotElf::Initialize() { kMaxNoteSize); std::string desc; VMAddress info_address; - if (notes->NextNote(nullptr, nullptr, &desc) == + VMAddress desc_address; + if (notes->NextNote(nullptr, nullptr, &desc, &desc_address) == ElfImageReader::NoteReader::Result::kSuccess) { - info_address = *reinterpret_cast<VMAddress*>(&desc[0]); + VMOffset offset; + if (elf_reader_->Memory()->Is64Bit()) { + offset = *reinterpret_cast<VMOffset*>(&desc[0]); + } else { + int32_t offset32 = *reinterpret_cast<int32_t*>(&desc[0]); + offset = offset32; + } + info_address = desc_address + offset; ProcessMemoryRange range; if (range.Initialize(*elf_reader_->Memory())) { @@ -145,7 +153,8 @@ void ModuleSnapshotElf::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const { std::unique_ptr<ElfImageReader::NoteReader> notes = elf_reader_->NotesWithNameAndType(ELF_NOTE_GNU, NT_GNU_BUILD_ID, 64); std::string desc; - notes->NextNote(nullptr, nullptr, &desc); + VMAddress desc_addr; + notes->NextNote(nullptr, nullptr, &desc, &desc_addr); desc.insert(desc.end(), 16 - std::min(desc.size(), size_t{16}), '\0'); uuid->InitializeFromBytes(reinterpret_cast<const uint8_t*>(&desc[0])); From 8c0d3d2c1e8c7c57ad2f9b994830dbf075b11142 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Wed, 31 Oct 2018 16:52:10 -0700 Subject: [PATCH 060/401] [fuchsia] support general registers for arm64 Bug: fuchsia:DX-639 Change-Id: Iaf44fffc6adc11025a37f3a62676cdebff435002 Tested: CQ; `crasher` on Fuchsia device (report id 27fac91e5550ea06) Reviewed-on: https://chromium-review.googlesource.com/c/1309159 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/fuchsia/cpu_context_fuchsia.cc | 32 ++++++++++++++++++- snapshot/fuchsia/cpu_context_fuchsia.h | 17 +++++++++- .../fuchsia/exception_snapshot_fuchsia.cc | 11 ++++--- snapshot/fuchsia/thread_snapshot_fuchsia.cc | 10 +++--- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/snapshot/fuchsia/cpu_context_fuchsia.cc b/snapshot/fuchsia/cpu_context_fuchsia.cc index 5a02f62f..4091921a 100644 --- a/snapshot/fuchsia/cpu_context_fuchsia.cc +++ b/snapshot/fuchsia/cpu_context_fuchsia.cc @@ -21,7 +21,7 @@ namespace internal { #if defined(ARCH_CPU_X86_64) -void InitializeCPUContextX86_64( +void InitializeCPUContextX86_64_NoFloatingPoint( const zx_thread_state_general_regs_t& thread_context, CPUContextX86_64* context) { memset(context, 0, sizeof(*context)); @@ -45,6 +45,36 @@ void InitializeCPUContextX86_64( context->rflags = thread_context.rflags; } +#elif defined(ARCH_CPU_ARM64) + +void InitializeCPUContextARM64_NoFloatingPoint( + const zx_thread_state_general_regs_t& thread_context, + CPUContextARM64* context) { + memset(context, 0, sizeof(*context)); + + // Fuchsia stores the link register (x30) on its own while Crashpad stores it + // with the other general purpose x0-x28 and x29 frame pointer registers. So + // we expect the size and number of elements to be off by one unit. + static_assert(sizeof(context->regs) - sizeof(context->regs[30]) == + sizeof(thread_context.r), + "registers size mismatch"); + static_assert((sizeof(context->regs) - sizeof(context->regs[30])) / + sizeof(context->regs[0]) == + sizeof(thread_context.r) / sizeof(thread_context.r[0]), + "registers number of elements mismatch"); + memcpy(&context->regs, &thread_context.r, sizeof(thread_context.r)); + context->regs[30] = thread_context.lr; + context->sp = thread_context.sp; + context->pc = thread_context.pc; + + // Only the NZCV flags (bits 31 to 28 respectively) of the cpsr register are + // readable and writable by userland on ARM64. + constexpr uint64_t kNZCV = 0xf0000000; + // Fuchsia uses the "cspr" terminology while Crashpad uses the "pstate" + // terminology. For the NZCV flags, the bit layout should be the same. + context->pstate = thread_context.cpsr & kNZCV; +} + #endif // ARCH_CPU_X86_64 } // namespace internal diff --git a/snapshot/fuchsia/cpu_context_fuchsia.h b/snapshot/fuchsia/cpu_context_fuchsia.h index f5336fdd..d81a3224 100644 --- a/snapshot/fuchsia/cpu_context_fuchsia.h +++ b/snapshot/fuchsia/cpu_context_fuchsia.h @@ -34,12 +34,27 @@ namespace internal { //! //! \param[in] thread_context The native thread context. //! \param[out] context The CPUContextX86_64 structure to initialize. -void InitializeCPUContextX86_64( +void InitializeCPUContextX86_64_NoFloatingPoint( const zx_thread_state_general_regs_t& thread_context, CPUContextX86_64* context); #endif // ARCH_CPU_X86_64 || DOXYGEN +#if defined(ARCH_CPU_ARM64) || DOXYGEN + +//! \brief Initializes a CPUContextARM64 structure from native context +//! structures on Fuchsia. +//! +//! Floating point registers are currently initialized to zero. +//! +//! \param[in] thread_context The native thread context. +//! \param[out] context The CPUContextARM64 structure to initialize. +void InitializeCPUContextARM64_NoFloatingPoint( + const zx_thread_state_general_regs_t& thread_context, + CPUContextARM64* context); + +#endif // ARCH_CPU_ARM64 || DOXYGEN + } // namespace internal } // namespace crashpad diff --git a/snapshot/fuchsia/exception_snapshot_fuchsia.cc b/snapshot/fuchsia/exception_snapshot_fuchsia.cc index 44b4e5cd..0bd08bb7 100644 --- a/snapshot/fuchsia/exception_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/exception_snapshot_fuchsia.cc @@ -59,13 +59,15 @@ void ExceptionSnapshotFuchsia::Initialize( #if defined(ARCH_CPU_X86_64) context_.architecture = kCPUArchitectureX86_64; context_.x86_64 = &context_arch_; - // TODO(scottmg): Float context, once Fuchsia has a debug API to capture - // floating point registers. ZX-1750 upstream. - InitializeCPUContextX86_64(t.general_registers, context_.x86_64); + // TODO(fuchsia/DX-642): Add float context once saved in |t|. + InitializeCPUContextX86_64_NoFloatingPoint(t.general_registers, + context_.x86_64); #elif defined(ARCH_CPU_ARM64) context_.architecture = kCPUArchitectureARM64; context_.arm64 = &context_arch_; - // TODO(scottmg): Implement context capture for arm64. + // TODO(fuchsia/DX-642): Add float context once saved in |t|. + InitializeCPUContextARM64_NoFloatingPoint(t.general_registers, + context_.arm64); #else #error Port. #endif @@ -85,7 +87,6 @@ void ExceptionSnapshotFuchsia::Initialize( #endif } - INITIALIZATION_STATE_SET_VALID(initialized_); } diff --git a/snapshot/fuchsia/thread_snapshot_fuchsia.cc b/snapshot/fuchsia/thread_snapshot_fuchsia.cc index 03055d8c..1cc09af5 100644 --- a/snapshot/fuchsia/thread_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/thread_snapshot_fuchsia.cc @@ -39,13 +39,15 @@ bool ThreadSnapshotFuchsia::Initialize( #if defined(ARCH_CPU_X86_64) context_.architecture = kCPUArchitectureX86_64; context_.x86_64 = &context_arch_; - // TODO(scottmg): Float context, once Fuchsia has a debug API to capture - // floating point registers. ZX-1750 upstream. - InitializeCPUContextX86_64(thread.general_registers, context_.x86_64); + // TODO(fuchsia/DX-642): Add float context once saved in |thread|. + InitializeCPUContextX86_64_NoFloatingPoint(thread.general_registers, + context_.x86_64); #elif defined(ARCH_CPU_ARM64) context_.architecture = kCPUArchitectureARM64; context_.arm64 = &context_arch_; - // TODO(scottmg): Implement context capture for arm64. + // TODO(fuchsia/DX-642): Add float context once saved in |thread|. + InitializeCPUContextARM64_NoFloatingPoint(thread.general_registers, + context_.arm64); #else #error Port. #endif From a4754a9ae94b7973406699c25517377162365196 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Thu, 1 Nov 2018 10:41:15 -0700 Subject: [PATCH 061/401] [snapshot][arm64] rename CPU context pstate to spsr * upon exception, the process state ("pstate") is stored in the saved process status register ("spsr") so the register we are manipulating is really just the SPSR * https://developer.arm.com/products/architecture/cpu-architecture/a-profile/docs/100878/latest/the-saved-process-status-register Change-Id: I9ce612c00b7a56a0f6d778d974ff9e0e5402ca5e Reviewed-on: https://chromium-review.googlesource.com/c/1312193 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- minidump/minidump_context_writer.cc | 8 +------- snapshot/cpu_context.h | 2 +- snapshot/fuchsia/cpu_context_fuchsia.cc | 15 +++++++++++---- snapshot/linux/cpu_context_linux.cc | 10 ++++++++-- snapshot/linux/exception_snapshot_linux_test.cc | 4 ++-- .../minidump/process_snapshot_minidump_test.cc | 2 +- snapshot/minidump/thread_snapshot_minidump.cc | 5 +---- snapshot/test/test_cpu_context.cc | 2 +- util/misc/capture_context_fuchsia.S | 2 +- util/misc/capture_context_linux.S | 2 +- 10 files changed, 28 insertions(+), 24 deletions(-) diff --git a/minidump/minidump_context_writer.cc b/minidump/minidump_context_writer.cc index b67e2bfe..d7e53a49 100644 --- a/minidump/minidump_context_writer.cc +++ b/minidump/minidump_context_writer.cc @@ -323,13 +323,6 @@ void MinidumpContextARM64Writer::InitializeFromSnapshot( context_.context_flags = kMinidumpContextARM64Full; - if (context_snapshot->pstate > - std::numeric_limits<decltype(context_.cpsr)>::max()) { - LOG(WARNING) << "pstate truncation"; - } - context_.cpsr = - static_cast<decltype(context_.cpsr)>(context_snapshot->pstate); - static_assert( sizeof(context_.regs) == sizeof(context_snapshot->regs) - 2 * sizeof(context_snapshot->regs[0]), @@ -339,6 +332,7 @@ void MinidumpContextARM64Writer::InitializeFromSnapshot( context_.lr = context_snapshot->regs[30]; context_.sp = context_snapshot->sp; context_.pc = context_snapshot->pc; + context_.cpsr = context_snapshot->spsr; static_assert(sizeof(context_.fpsimd) == sizeof(context_snapshot->fpsimd), "FPSIMD size mismatch"); diff --git a/snapshot/cpu_context.h b/snapshot/cpu_context.h index 4dde9436..fb23c467 100644 --- a/snapshot/cpu_context.h +++ b/snapshot/cpu_context.h @@ -299,7 +299,7 @@ struct CPUContextARM64 { uint64_t regs[31]; uint64_t sp; uint64_t pc; - uint64_t pstate; + uint32_t spsr; uint128_struct fpsimd[32]; uint32_t fpsr; diff --git a/snapshot/fuchsia/cpu_context_fuchsia.cc b/snapshot/fuchsia/cpu_context_fuchsia.cc index 4091921a..f4e3be63 100644 --- a/snapshot/fuchsia/cpu_context_fuchsia.cc +++ b/snapshot/fuchsia/cpu_context_fuchsia.cc @@ -69,10 +69,17 @@ void InitializeCPUContextARM64_NoFloatingPoint( // Only the NZCV flags (bits 31 to 28 respectively) of the cpsr register are // readable and writable by userland on ARM64. - constexpr uint64_t kNZCV = 0xf0000000; - // Fuchsia uses the "cspr" terminology while Crashpad uses the "pstate" - // terminology. For the NZCV flags, the bit layout should be the same. - context->pstate = thread_context.cpsr & kNZCV; + constexpr uint32_t kNZCV = 0xf0000000; + // Fuchsia uses the old "cspr" terminology from armv7 while Crashpad uses the + // new "spsr" terminology for armv8. + context->spsr = thread_context.cpsr & kNZCV; + if (thread_context.cpsr > + std::numeric_limits<decltype(context->spsr)>::max()) { + LOG(WARNING) << "cpsr truncation: we only expect the first 32 bits to be " + "set in the cpsr"; + } + context->spsr = + static_cast<decltype(context->spsr)>(thread_context.cpsr) & kNZCV; } #endif // ARCH_CPU_X86_64 diff --git a/snapshot/linux/cpu_context_linux.cc b/snapshot/linux/cpu_context_linux.cc index ebf9d7e9..6ba52a8d 100644 --- a/snapshot/linux/cpu_context_linux.cc +++ b/snapshot/linux/cpu_context_linux.cc @@ -62,7 +62,6 @@ void InitializeCPUContextX86(const ThreadContext::t32_t& thread_context, context->dr5 = 0; context->dr6 = 0; context->dr7 = 0; - } void InitializeCPUContextX86(const SignalThreadContext32& thread_context, @@ -241,7 +240,14 @@ void InitializeCPUContextARM64_NoFloatingPoint( memcpy(context->regs, thread_context.regs, sizeof(context->regs)); context->sp = thread_context.sp; context->pc = thread_context.pc; - context->pstate = thread_context.pstate; + // Linux seems to only be putting the SPSR register in its "pstate" field. + // https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/uapi/asm/ptrace.h + if (thread_context.pstate > + std::numeric_limits<decltype(context->spsr)>::max()) { + LOG(WARNING) << "pstate truncation: we only expect the SPSR bits to be set " + "in the pstate"; + } + context->spsr = static_cast<decltype(context->spsr)>(thread_context.pstate); memset(&context->fpsimd, 0, sizeof(context->fpsimd)); context->fpsr = 0; diff --git a/snapshot/linux/exception_snapshot_linux_test.cc b/snapshot/linux/exception_snapshot_linux_test.cc index df9ad9e9..cc09dd7e 100644 --- a/snapshot/linux/exception_snapshot_linux_test.cc +++ b/snapshot/linux/exception_snapshot_linux_test.cc @@ -224,7 +224,7 @@ void InitializeContext(NativeCPUContext* context) { } context->uc_mcontext.sp = 1; context->uc_mcontext.pc = 2; - context->uc_mcontext.pstate = 3; + context->uc_mcontext.spsr = 3; auto test_context = reinterpret_cast<TestCoprocessorContext*>( context->uc_mcontext.__reserved); @@ -254,7 +254,7 @@ void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) { 0); EXPECT_EQ(actual.arm64->sp, expected.uc_mcontext.sp); EXPECT_EQ(actual.arm64->pc, expected.uc_mcontext.pc); - EXPECT_EQ(actual.arm64->pstate, expected.uc_mcontext.pstate); + EXPECT_EQ(actual.arm64->spsr, expected.uc_mcontext.spsr); auto test_context = reinterpret_cast<const TestCoprocessorContext*>( expected.uc_mcontext.__reserved); diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 79b81859..5ede5890 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -761,7 +761,7 @@ TEST(ProcessSnapshotMinidump, ThreadContextARM64) { const CPUContextARM64* ctx = ctx_generic->arm64; - EXPECT_EQ(ctx->pstate, 0UL); + EXPECT_EQ(ctx->spsr, 0UL); for (unsigned int i = 0; i < 31; i++) { EXPECT_EQ(ctx->regs[i], i + 1); diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc index ddc15cf1..00e0e9bf 100644 --- a/snapshot/minidump/thread_snapshot_minidump.cc +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -239,10 +239,7 @@ bool ThreadSnapshotMinidump::InitializeContext( context_.arm64->pc = src->pc; context_.arm64->fpcr = src->fpcr; context_.arm64->fpsr = src->fpsr; - - // Seems we don't get a full PSTATE but it looks like this assignment - // should give something useful at least. - context_.arm64->pstate = src->cpsr; + context_.arm64->spsr = src->cpsr; } else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPSEL) { LOG(WARNING) << "Snapshot MIPS context support has no unit tests."; context_memory_.resize(sizeof(CPUContextMIPS)); diff --git a/snapshot/test/test_cpu_context.cc b/snapshot/test/test_cpu_context.cc index 1e785af8..8e712b7a 100644 --- a/snapshot/test/test_cpu_context.cc +++ b/snapshot/test/test_cpu_context.cc @@ -210,7 +210,7 @@ void InitializeCPUContextARM64(CPUContext* context, uint32_t seed) { } arm64->sp = value++; arm64->pc = value++; - arm64->pstate = value++; + arm64->spsr = value++; for (size_t index = 0; index < arraysize(arm64->fpsimd); ++index) { arm64->fpsimd[index].lo = value++; diff --git a/util/misc/capture_context_fuchsia.S b/util/misc/capture_context_fuchsia.S index 8e5c0cbe..21aefad0 100644 --- a/util/misc/capture_context_fuchsia.S +++ b/util/misc/capture_context_fuchsia.S @@ -159,7 +159,7 @@ CAPTURECONTEXT_SYMBOL: // The link register holds the return address for this function. str LR, [x0, #0x1b8] // context->uc_mcontext.pc - // NZCV, pstate, and CPSR are synonyms. + // pstate should hold SPSR but NZCV are the only bits we know about. mrs x1, NZCV str x1, [x0, #0x1c0] // context->uc_mcontext.pstate diff --git a/util/misc/capture_context_linux.S b/util/misc/capture_context_linux.S index f4216fd1..657a979a 100644 --- a/util/misc/capture_context_linux.S +++ b/util/misc/capture_context_linux.S @@ -319,7 +319,7 @@ CAPTURECONTEXT_SYMBOL2: // The link register holds the return address for this function. str x30, [x0, #0x1b8] // context->uc_mcontext.pc - // NZCV, pstate, and CPSR are synonyms. + // pstate should hold SPSR but NZCV are the only bits we know about. mrs x1, NZCV str x1, [x0, #0x1c0] // context->uc_mcontext.pstate From 9d4afb05820f2ece10d0cf168525732409c5512a Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Thu, 1 Nov 2018 12:27:34 -0700 Subject: [PATCH 062/401] [fuchsia][arm64] support vector registers Bug: fuchsia:DX-642 Change-Id: I898b75e47d0dd810025db6ea27e2e0e73ec82768 Tested: CQ Reviewed-on: https://chromium-review.googlesource.com/c/1310513 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/fuchsia/cpu_context_fuchsia.cc | 9 +++++++- snapshot/fuchsia/cpu_context_fuchsia.h | 7 ++++--- .../fuchsia/exception_snapshot_fuchsia.cc | 5 ++--- snapshot/fuchsia/process_reader_fuchsia.cc | 21 ++++++++++++++----- snapshot/fuchsia/process_reader_fuchsia.h | 4 ++++ snapshot/fuchsia/thread_snapshot_fuchsia.cc | 5 ++--- 6 files changed, 36 insertions(+), 15 deletions(-) diff --git a/snapshot/fuchsia/cpu_context_fuchsia.cc b/snapshot/fuchsia/cpu_context_fuchsia.cc index f4e3be63..226bfc67 100644 --- a/snapshot/fuchsia/cpu_context_fuchsia.cc +++ b/snapshot/fuchsia/cpu_context_fuchsia.cc @@ -47,8 +47,9 @@ void InitializeCPUContextX86_64_NoFloatingPoint( #elif defined(ARCH_CPU_ARM64) -void InitializeCPUContextARM64_NoFloatingPoint( +void InitializeCPUContextARM64( const zx_thread_state_general_regs_t& thread_context, + const zx_thread_state_vector_regs_t& vector_context, CPUContextARM64* context) { memset(context, 0, sizeof(*context)); @@ -80,6 +81,12 @@ void InitializeCPUContextARM64_NoFloatingPoint( } context->spsr = static_cast<decltype(context->spsr)>(thread_context.cpsr) & kNZCV; + + context->fpcr = vector_context.fpcr; + context->fpsr = vector_context.fpsr; + static_assert(sizeof(context->fpsimd) == sizeof(vector_context.v), + "registers size mismatch"); + memcpy(&context->fpsimd, &vector_context.v, sizeof(vector_context.v)); } #endif // ARCH_CPU_X86_64 diff --git a/snapshot/fuchsia/cpu_context_fuchsia.h b/snapshot/fuchsia/cpu_context_fuchsia.h index d81a3224..9227bfc8 100644 --- a/snapshot/fuchsia/cpu_context_fuchsia.h +++ b/snapshot/fuchsia/cpu_context_fuchsia.h @@ -45,12 +45,13 @@ void InitializeCPUContextX86_64_NoFloatingPoint( //! \brief Initializes a CPUContextARM64 structure from native context //! structures on Fuchsia. //! -//! Floating point registers are currently initialized to zero. -//! //! \param[in] thread_context The native thread context. +//! \param[in] vector_context The native vector context that also contains the +//! floating point registers. //! \param[out] context The CPUContextARM64 structure to initialize. -void InitializeCPUContextARM64_NoFloatingPoint( +void InitializeCPUContextARM64( const zx_thread_state_general_regs_t& thread_context, + const zx_thread_state_vector_regs_t& vector_context, CPUContextARM64* context); #endif // ARCH_CPU_ARM64 || DOXYGEN diff --git a/snapshot/fuchsia/exception_snapshot_fuchsia.cc b/snapshot/fuchsia/exception_snapshot_fuchsia.cc index 0bd08bb7..f70b9660 100644 --- a/snapshot/fuchsia/exception_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/exception_snapshot_fuchsia.cc @@ -65,9 +65,8 @@ void ExceptionSnapshotFuchsia::Initialize( #elif defined(ARCH_CPU_ARM64) context_.architecture = kCPUArchitectureARM64; context_.arm64 = &context_arch_; - // TODO(fuchsia/DX-642): Add float context once saved in |t|. - InitializeCPUContextARM64_NoFloatingPoint(t.general_registers, - context_.arm64); + InitializeCPUContextARM64( + t.general_registers, t.vector_registers, context_.arm64); #else #error Port. #endif diff --git a/snapshot/fuchsia/process_reader_fuchsia.cc b/snapshot/fuchsia/process_reader_fuchsia.cc index 40123018..e60766af 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.cc +++ b/snapshot/fuchsia/process_reader_fuchsia.cc @@ -276,15 +276,26 @@ void ProcessReaderFuchsia::InitializeThreads() { thread.state = thread_info.state; } - zx_thread_state_general_regs_t regs; + zx_thread_state_general_regs_t general_regs; status = thread_handles[i].read_state( - ZX_THREAD_STATE_GENERAL_REGS, ®s, sizeof(regs)); + ZX_THREAD_STATE_GENERAL_REGS, &general_regs, sizeof(general_regs)); if (status != ZX_OK) { - ZX_LOG(WARNING, status) << "zx_thread_read_state"; + ZX_LOG(WARNING, status) + << "zx_thread_read_state(ZX_THREAD_STATE_GENERAL_REGS)"; } else { - thread.general_registers = regs; + thread.general_registers = general_regs; - GetStackRegions(regs, memory_map_, &thread.stack_regions); + GetStackRegions(general_regs, memory_map_, &thread.stack_regions); + } + + zx_thread_state_vector_regs_t vector_regs; + status = thread_handles[i].read_state( + ZX_THREAD_STATE_VECTOR_REGS, &vector_regs, sizeof(vector_regs)); + if (status != ZX_OK) { + ZX_LOG(WARNING, status) + << "zx_thread_read_state(ZX_THREAD_STATE_VECTOR_REGS)"; + } else { + thread.vector_registers = vector_regs; } } diff --git a/snapshot/fuchsia/process_reader_fuchsia.h b/snapshot/fuchsia/process_reader_fuchsia.h index 6a6a6509..28a1e93e 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.h +++ b/snapshot/fuchsia/process_reader_fuchsia.h @@ -77,6 +77,10 @@ class ProcessReaderFuchsia { //! returned by `zx_thread_read_state()`. zx_thread_state_general_regs_t general_registers = {}; + //! \brief The raw architecture-specific `zx_thread_state_vector_regs_t` as + //! returned by `zx_thread_read_state()`. + zx_thread_state_vector_regs_t vector_registers = {}; + //! \brief The regions representing the stack. The first entry in the vector //! represents the callstack, and further entries optionally identify //! other stack data when the thread uses a split stack representation. diff --git a/snapshot/fuchsia/thread_snapshot_fuchsia.cc b/snapshot/fuchsia/thread_snapshot_fuchsia.cc index 1cc09af5..b3a4cec1 100644 --- a/snapshot/fuchsia/thread_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/thread_snapshot_fuchsia.cc @@ -45,9 +45,8 @@ bool ThreadSnapshotFuchsia::Initialize( #elif defined(ARCH_CPU_ARM64) context_.architecture = kCPUArchitectureARM64; context_.arm64 = &context_arch_; - // TODO(fuchsia/DX-642): Add float context once saved in |thread|. - InitializeCPUContextARM64_NoFloatingPoint(thread.general_registers, - context_.arm64); + InitializeCPUContextARM64( + thread.general_registers, thread.vector_registers, context_.arm64); #else #error Port. #endif From dc0052bd43ebef0944f79ec6bfafe8bdc72242c8 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 2 Nov 2018 10:18:28 -0700 Subject: [PATCH 063/401] Fuchsia: Use SDK manifest for CC prebuilt and source packages Upstreams: https://chromium-review.googlesource.com/c/chromium/src/+/1292570 Change-Id: I366651f57076dd0e854daa6f23a6dfa47babf60d Reviewed-on: https://chromium-review.googlesource.com/c/1315432 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- third_party/fuchsia/BUILD.gn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index a1ee935e..f2b8174d 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -25,8 +25,8 @@ if (crashpad_is_in_fuchsia) { } else if (crashpad_is_in_chromium) { group("zx") { public_deps = [ - "//third_party/fuchsia-sdk:fdio", - "//third_party/fuchsia-sdk:zx", + "//third_party/fuchsia-sdk/sdk:fdio", + "//third_party/fuchsia-sdk/sdk:zx", "//third_party/fuchsia-sdk/sdk:sysinfo", ] } From 0b19010fba9f07b2d925dd0d0f2a40dc116a21e6 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 2 Nov 2018 11:01:15 -0700 Subject: [PATCH 064/401] Include windows.h before dbghelp.h dbghelp.h requires windows.h to have been included. Change-Id: I66d40e396d60cafe99c2480fdfbf1a9114abe386 Reviewed-on: https://chromium-review.googlesource.com/c/1315787 Reviewed-by: Scott Graham <scottmg@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- snapshot/minidump/memory_snapshot_minidump.h | 1 + 1 file changed, 1 insertion(+) diff --git a/snapshot/minidump/memory_snapshot_minidump.h b/snapshot/minidump/memory_snapshot_minidump.h index f0b83c57..69521be0 100644 --- a/snapshot/minidump/memory_snapshot_minidump.h +++ b/snapshot/minidump/memory_snapshot_minidump.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_SNAPSHOT_MINIDUMP_MEMORY_SNAPSHOT_MINIDUMP_H_ #define CRASHPAD_SNAPSHOT_MINIDUMP_MEMORY_SNAPSHOT_MINIDUMP_H_ +#include <windows.h> #include <dbghelp.h> #include <vector> From da3c7e7ac508d4ecbd10c917e553a80597028aa6 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 2 Nov 2018 12:05:21 -0700 Subject: [PATCH 065/401] android: fix the build References to mcontext_t's pstate were mistakenly changed to spsr here: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1312193 Also Android's time_t is a signed type. Change-Id: I4cf83d57b70dced9360a816e87c30a4aaba778ca Reviewed-on: https://chromium-review.googlesource.com/c/1315789 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- snapshot/linux/exception_snapshot_linux_test.cc | 4 ++-- snapshot/minidump/process_snapshot_minidump_test.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/snapshot/linux/exception_snapshot_linux_test.cc b/snapshot/linux/exception_snapshot_linux_test.cc index cc09dd7e..72d36d8a 100644 --- a/snapshot/linux/exception_snapshot_linux_test.cc +++ b/snapshot/linux/exception_snapshot_linux_test.cc @@ -224,7 +224,7 @@ void InitializeContext(NativeCPUContext* context) { } context->uc_mcontext.sp = 1; context->uc_mcontext.pc = 2; - context->uc_mcontext.spsr = 3; + context->uc_mcontext.pstate = 3; auto test_context = reinterpret_cast<TestCoprocessorContext*>( context->uc_mcontext.__reserved); @@ -254,7 +254,7 @@ void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) { 0); EXPECT_EQ(actual.arm64->sp, expected.uc_mcontext.sp); EXPECT_EQ(actual.arm64->pc, expected.uc_mcontext.pc); - EXPECT_EQ(actual.arm64->spsr, expected.uc_mcontext.spsr); + EXPECT_EQ(actual.arm64->spsr, expected.uc_mcontext.pstate); auto test_context = reinterpret_cast<const TestCoprocessorContext*>( expected.uc_mcontext.__reserved); diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 5ede5890..2268ac3d 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -454,7 +454,7 @@ TEST(ProcessSnapshotMinidump, Modules) { EXPECT_EQ(modules[i]->Name(), names[i]); EXPECT_EQ(modules[i]->Address(), 0xbadf00dU); EXPECT_EQ(modules[i]->Size(), 9001U); - EXPECT_EQ(modules[i]->Timestamp(), 1970U + i); + EXPECT_EQ(modules[i]->Timestamp(), static_cast<time_t>(1970U + i)); uint16_t v0; uint16_t v1; From 236ee1076c818de121a251661c41412377983405 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 31 Oct 2018 17:44:11 -0700 Subject: [PATCH 066/401] Roll mini_chromium to d2c271a d2c271a Add base::GetPageSize() a3e3e59 Remove MSVC_SUPPRESS_WARNING Bug: crashpad:262 Change-Id: I98f1a53e300556fed8780f6c58cc274a7ad2b43f Reviewed-on: https://chromium-review.googlesource.com/c/1312034 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 123daf62..6cfae819 100644 --- a/DEPS +++ b/DEPS @@ -30,7 +30,7 @@ deps = { '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '3577ffda752e26e506bb4971a8fb8bc67189ad1e', + 'd2c271a0671f81db24bce69631ba99d0c26f3a5b', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 9ee48fb1be75185d62d8dd86ba9cd76dd6008eb4 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Sat, 3 Nov 2018 03:16:40 +0000 Subject: [PATCH 067/401] Revert "Use a relative address in .note.crashpad.info" This reverts commit 95e97a32eba4d505ab9591e683d2147c441eea48. Reason for revert: arm64 lto build Original change's description: > Use a relative address in .note.crashpad.info > > The desc value in the note is now the offset of CRASHPAD_INFO_SYMBOL > from desc. > > Making this note writable can trigger a linker error resulting in > the binary embedding .note.crashpad.info to be rejected by the > kernel during program loading. > > The error was observed with: > GNU ld (GNU Binutils for Debian) 2.30 > clang version 4.0.1-10 (tags/RELEASE_401/final) > Debian 4.17.17-1rodete2 > > When the note is made writable, crashpad_snapshot_test contains two > PT_LOAD segments which map to the same page. > > LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 > 0x0000000000000258 0x0000000000000258 R 0x200000 > LOAD 0x0000000000000258 0x0000000000000258 0x0000000000000258 > 0x00000000002b84d8 0x00000000002b8950 RWE 0x200000 > > Executing this binary with the execv system call triggers a segfault > during program loading (an error can't be returned because the original > process vm has already been discarded). > > I suspect (I haven't set up a debuggable kernel) the failure occurs > while attempting to map the second load segment because its virtual > address, 0x258, is in the same page as the first load segment. > https://elixir.bootlin.com/linux/v4.17.17/source/fs/binfmt_elf.c#L380 > > The linker normally produces consecutive load segments where the second > segment is loaded 0x200000 bytes after the first, which I think is the > maximum expected page size. Modifying the test executable to load the > second segment at 0x1258 (4096 byte page size) allows program loading > to succeed (but of course crashes after control is given to it). > > Bug: crashpad:260 > Change-Id: I2b9f1e66e98919138baef3da991a9710bd970dc4 > Reviewed-on: https://chromium-review.googlesource.com/c/1292232 > Reviewed-by: Scott Graham <scottmg@chromium.org> > Reviewed-by: Mark Mentovai <mark@chromium.org> > Commit-Queue: Joshua Peraza <jperaza@chromium.org> TBR=scottmg@chromium.org,jperaza@chromium.org,mark@chromium.org # Not skipping CQ checks because original CL landed > 1 day ago. Bug: crashpad:260 Change-Id: I7a2c741e6b4c10d3e3b8be3213a8ce2cd93675f7 Reviewed-on: https://chromium-review.googlesource.com/c/1316372 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- client/crashpad_info_note.S | 18 +++++++++++------- snapshot/crashpad_info_size_test_note.S | 18 +++++++++++------- snapshot/elf/elf_image_reader.cc | 12 ++++-------- snapshot/elf/elf_image_reader.h | 16 ++++------------ snapshot/elf/elf_image_reader_fuzzer.cc | 4 +--- snapshot/elf/elf_image_reader_test.cc | 10 ++++------ snapshot/elf/module_snapshot_elf.cc | 15 +++------------ 7 files changed, 38 insertions(+), 55 deletions(-) diff --git a/client/crashpad_info_note.S b/client/crashpad_info_note.S index b60093c9..4c29298d 100644 --- a/client/crashpad_info_note.S +++ b/client/crashpad_info_note.S @@ -26,11 +26,9 @@ #define NOTE_ALIGN 4 // This section must be "a"llocated so that it appears in the final binary at - // runtime. The reference to CRASHPAD_INFO_SYMBOL uses an offset relative to - // this note to avoid making this note writable, which triggers a bug in GNU - // ld, or adding text relocations which require the target system to allow - // making text segments writable. https://crbug.com/crashpad/260. - .section .note.crashpad.info,"a",%note + // runtime, and "w"ritable so that the relocation to CRASHPAD_INFO_SYMBOL can + // be performed. + .section .note.crashpad.info,"aw",%note .balign NOTE_ALIGN # .globl indicates that it's available to link against other .o files. .hidden # indicates that it will not appear in the executable's symbol table. @@ -47,9 +45,15 @@ name_end: .balign NOTE_ALIGN desc: #if defined(__LP64__) - .quad CRASHPAD_INFO_SYMBOL - desc + .quad CRASHPAD_INFO_SYMBOL #else - .long CRASHPAD_INFO_SYMBOL - desc +#if defined(__LITTLE_ENDIAN__) + .long CRASHPAD_INFO_SYMBOL + .long 0 +#else + .long 0 + .long CRASHPAD_INFO_SYMBOL +#endif // __LITTLE_ENDIAN__ #endif // __LP64__ desc_end: .size CRASHPAD_NOTE_REFERENCE, .-CRASHPAD_NOTE_REFERENCE diff --git a/snapshot/crashpad_info_size_test_note.S b/snapshot/crashpad_info_size_test_note.S index 16b5d499..96b996db 100644 --- a/snapshot/crashpad_info_size_test_note.S +++ b/snapshot/crashpad_info_size_test_note.S @@ -26,11 +26,9 @@ #define NOTE_ALIGN 4 // This section must be "a"llocated so that it appears in the final binary at - // runtime. The reference to TEST_CRASHPAD_INFO_SYMBOL uses an offset relative - // to this note to avoid making this note writable, which triggers a bug in - // GNU ld, or adding text relocations which require the target system to allow - // making text segments writable. https://crbug.com/crashpad/260. - .section .note.crashpad.info,"a",%note + // runtime, and "w"ritable so that the relocation to TEST_CRASHPAD_INFO_SYMBOL + // can be performed. + .section .note.crashpad.info,"aw",%note .balign NOTE_ALIGN .type info_size_test_note, %object info_size_test_note: @@ -43,9 +41,15 @@ name_end: .balign NOTE_ALIGN desc: #if defined(__LP64__) - .quad TEST_CRASHPAD_INFO_SYMBOL - desc + .quad TEST_CRASHPAD_INFO_SYMBOL #else - .long TEST_CRASHPAD_INFO_SYMBOL - desc +#if defined(__LITTLE_ENDIAN__) + .long TEST_CRASHPAD_INFO_SYMBOL + .long 0 +#else + .long 0 + .long TEST_CRASHPAD_INFO_SYMBOL +#endif // __LITTLE_ENDIAN__ #endif // __LP64__ desc_end: .size info_size_test_note, .-info_size_test_note diff --git a/snapshot/elf/elf_image_reader.cc b/snapshot/elf/elf_image_reader.cc index ffe3f7b1..8ee51d34 100644 --- a/snapshot/elf/elf_image_reader.cc +++ b/snapshot/elf/elf_image_reader.cc @@ -191,8 +191,7 @@ ElfImageReader::NoteReader::~NoteReader() = default; ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::NextNote( std::string* name, NoteType* type, - std::string* desc, - VMAddress* desc_address) { + std::string* desc) { if (!is_valid_) { LOG(ERROR) << "invalid note reader"; return Result::kError; @@ -216,9 +215,8 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::NextNote( } retry_ = false; - result = range_->Is64Bit() - ? ReadNote<Elf64_Nhdr>(name, type, desc, desc_address) - : ReadNote<Elf32_Nhdr>(name, type, desc, desc_address); + result = range_->Is64Bit() ? ReadNote<Elf64_Nhdr>(name, type, desc) + : ReadNote<Elf32_Nhdr>(name, type, desc); } while (retry_); if (result == Result::kSuccess) { @@ -253,8 +251,7 @@ template <typename NhdrType> ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( std::string* name, NoteType* type, - std::string* desc, - VMAddress* desc_address) { + std::string* desc) { static_assert(sizeof(*type) >= sizeof(NhdrType::n_namesz), "Note field size mismatch"); DCHECK_LT(current_address_, segment_end_address_); @@ -320,7 +317,6 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( current_address_, note_info.n_descsz, &local_desc[0])) { return Result::kError; } - *desc_address = current_address_; current_address_ = end_of_note; diff --git a/snapshot/elf/elf_image_reader.h b/snapshot/elf/elf_image_reader.h index f35c7616..317b35ad 100644 --- a/snapshot/elf/elf_image_reader.h +++ b/snapshot/elf/elf_image_reader.h @@ -70,14 +70,9 @@ class ElfImageReader { //! \param[out] name The name of the note owner, if not `nullptr`. //! \param[out] type A type for the note, if not `nullptr`. //! \param[out] desc The note descriptor. - //! \param[out] desc_addr The address in the remote process' address space - //! \a desc was read from. - //! \return a #Result value. \a name, \a type, \a desc, and \a desc_addr are - //! only valid if this method returns Result::kSuccess. - Result NextNote(std::string* name, - NoteType* type, - std::string* desc, - VMAddress* desc_addr); + //! \return a #Result value. \a name, \a type, and \a desc are only valid if + //! this method returns Result::kSuccess. + Result NextNote(std::string* name, NoteType* type, std::string* desc); // private NoteReader(const ElfImageReader* elf_reader_, @@ -93,10 +88,7 @@ class ElfImageReader { // and returns kError if use_filter_ is true and the note's name and type do // not match name_filter_ and type_filter_. template <typename T> - Result ReadNote(std::string* name, - NoteType* type, - std::string* desc, - VMAddress* desc_addr); + Result ReadNote(std::string* name, NoteType* type, std::string* desc); VMAddress current_address_; VMAddress segment_end_address_; diff --git a/snapshot/elf/elf_image_reader_fuzzer.cc b/snapshot/elf/elf_image_reader_fuzzer.cc index 73bded72..1686650b 100644 --- a/snapshot/elf/elf_image_reader_fuzzer.cc +++ b/snapshot/elf/elf_image_reader_fuzzer.cc @@ -65,10 +65,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { std::string note_name; std::string note_desc; ElfImageReader::NoteReader::NoteType note_type; - VMAddress desc_addr; auto notes = reader.Notes(-1); - while ((result = notes->NextNote( - ¬e_name, ¬e_type, ¬e_desc, &desc_addr)) == + while ((result = notes->NextNote(¬e_name, ¬e_type, ¬e_desc)) == ElfImageReader::NoteReader::Result::kSuccess) { LOG(ERROR) << note_name << note_type << note_desc; } diff --git a/snapshot/elf/elf_image_reader_test.cc b/snapshot/elf/elf_image_reader_test.cc index 2cc0faa5..6d88d817 100644 --- a/snapshot/elf/elf_image_reader_test.cc +++ b/snapshot/elf/elf_image_reader_test.cc @@ -154,24 +154,22 @@ void ReadThisExecutableInTarget(ProcessType process, std::string note_name; std::string note_desc; ElfImageReader::NoteReader::NoteType note_type; - VMAddress desc_addr; std::unique_ptr<ElfImageReader::NoteReader> notes = reader.Notes(-1); - while ((result = notes->NextNote( - ¬e_name, ¬e_type, ¬e_desc, &desc_addr)) == + while ((result = notes->NextNote(¬e_name, ¬e_type, ¬e_desc)) == ElfImageReader::NoteReader::Result::kSuccess) { } EXPECT_EQ(result, ElfImageReader::NoteReader::Result::kNoMoreNotes); notes = reader.Notes(0); - EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), + EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc), ElfImageReader::NoteReader::Result::kNoMoreNotes); // Find the note defined in elf_image_reader_test_note.S. constexpr uint32_t kCrashpadNoteDesc = 42; notes = reader.NotesWithNameAndType( CRASHPAD_ELF_NOTE_NAME, CRASHPAD_ELF_NOTE_TYPE_SNAPSHOT_TEST, -1); - ASSERT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), + ASSERT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc), ElfImageReader::NoteReader::Result::kSuccess); EXPECT_EQ(note_name, CRASHPAD_ELF_NOTE_NAME); EXPECT_EQ(note_type, @@ -180,7 +178,7 @@ void ReadThisExecutableInTarget(ProcessType process, EXPECT_EQ(*reinterpret_cast<decltype(kCrashpadNoteDesc)*>(¬e_desc[0]), kCrashpadNoteDesc); - EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), + EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc), ElfImageReader::NoteReader::Result::kNoMoreNotes); } diff --git a/snapshot/elf/module_snapshot_elf.cc b/snapshot/elf/module_snapshot_elf.cc index 39385a6d..62a961d3 100644 --- a/snapshot/elf/module_snapshot_elf.cc +++ b/snapshot/elf/module_snapshot_elf.cc @@ -56,17 +56,9 @@ bool ModuleSnapshotElf::Initialize() { kMaxNoteSize); std::string desc; VMAddress info_address; - VMAddress desc_address; - if (notes->NextNote(nullptr, nullptr, &desc, &desc_address) == + if (notes->NextNote(nullptr, nullptr, &desc) == ElfImageReader::NoteReader::Result::kSuccess) { - VMOffset offset; - if (elf_reader_->Memory()->Is64Bit()) { - offset = *reinterpret_cast<VMOffset*>(&desc[0]); - } else { - int32_t offset32 = *reinterpret_cast<int32_t*>(&desc[0]); - offset = offset32; - } - info_address = desc_address + offset; + info_address = *reinterpret_cast<VMAddress*>(&desc[0]); ProcessMemoryRange range; if (range.Initialize(*elf_reader_->Memory())) { @@ -153,8 +145,7 @@ void ModuleSnapshotElf::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const { std::unique_ptr<ElfImageReader::NoteReader> notes = elf_reader_->NotesWithNameAndType(ELF_NOTE_GNU, NT_GNU_BUILD_ID, 64); std::string desc; - VMAddress desc_addr; - notes->NextNote(nullptr, nullptr, &desc, &desc_addr); + notes->NextNote(nullptr, nullptr, &desc); desc.insert(desc.end(), 16 - std::min(desc.size(), size_t{16}), '\0'); uuid->InitializeFromBytes(reinterpret_cast<const uint8_t*>(&desc[0])); From a008d8a151e2c316ac9f20c84fcc5306c080e5d9 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Mon, 5 Nov 2018 11:08:36 -0800 Subject: [PATCH 068/401] Make Windows bots non-experimental In the transition from Buildbot to LUCI, the Windows bots were temporarily marked experimental. They should not be and should block the CQ if failing. Bug: crashpad:264 Change-Id: I781d70b323fb34209916f46c0dcf2235a95876fa Reviewed-on: https://chromium-review.googlesource.com/c/1318386 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- infra/config/cq.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg index c6c8a396..c0522b47 100644 --- a/infra/config/cq.cfg +++ b/infra/config/cq.cfg @@ -34,8 +34,8 @@ verifiers { name: "luci.crashpad.try" builders { name: "crashpad_try_mac_dbg" } builders { name: "crashpad_try_mac_rel" } - builders { name: "crashpad_try_win_dbg" experiment_percentage: 100 } - builders { name: "crashpad_try_win_rel" experiment_percentage: 100 } + builders { name: "crashpad_try_win_dbg" } + builders { name: "crashpad_try_win_rel" } builders { name: "crashpad_try_linux_dbg" } builders { name: "crashpad_try_linux_rel" } builders { name: "crashpad_try_fuchsia_arm64_dbg" } From 1b20b620cfc97c5270e6f6db2677cb948c8627ef Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Mon, 5 Nov 2018 11:13:37 -0800 Subject: [PATCH 069/401] Fix 32-bit Windows downcast build failure Bug: crashpad:264 Change-Id: Ie185fbe6fe909568b7364496586fb950c074674f Reviewed-on: https://chromium-review.googlesource.com/c/1318378 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/minidump/memory_snapshot_minidump.cc | 5 ++++- snapshot/minidump/process_snapshot_minidump_test.cc | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/snapshot/minidump/memory_snapshot_minidump.cc b/snapshot/minidump/memory_snapshot_minidump.cc index 37f54a2d..2c6c899a 100644 --- a/snapshot/minidump/memory_snapshot_minidump.cc +++ b/snapshot/minidump/memory_snapshot_minidump.cc @@ -16,6 +16,8 @@ #include <memory> +#include "base/numerics/safe_math.h" + namespace crashpad { namespace internal { @@ -98,7 +100,8 @@ const MemorySnapshot* MemorySnapshotMinidump::MergeWithOtherSnapshot( return result.release(); } - result->data_.resize(other_cast->address_ - address_); + result->data_.resize( + base::checked_cast<size_t>(other_cast->address_ - address_)); result->data_.insert(result->data_.end(), other_cast->data_.begin(), other_cast->data_.end()); return result.release(); diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 2268ac3d..4d744545 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -20,11 +20,12 @@ #include <memory> +#include "base/numerics/safe_math.h" #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" #include "minidump/minidump_context.h" -#include "snapshot/minidump/minidump_annotation_reader.h" #include "snapshot/memory_map_region_snapshot.h" +#include "snapshot/minidump/minidump_annotation_reader.h" #include "snapshot/module_snapshot.h" #include "util/file/string_file.h" #include "util/misc/pdb_structures.h" @@ -323,7 +324,8 @@ TEST(ProcessSnapshotMinidump, Modules) { for (uint32_t i = 0; i < minidump_module_count; i++) { name_rvas[i] = static_cast<RVA>(string_file.SeekGet()); auto name16 = base::UTF8ToUTF16(names[i]); - uint32_t size = sizeof(name16[0]) * name16.size(); + uint32_t size = + base::checked_cast<uint32_t>(sizeof(name16[0]) * name16.size()); EXPECT_TRUE(string_file.Write(&size, sizeof(size))); EXPECT_TRUE(string_file.Write(&name16[0], size)); } @@ -1066,7 +1068,8 @@ TEST(ProcessSnapshotMinidump, Stacks) { '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - minidump_thread.Stack.Memory.DataSize = minidump_stack.size(); + minidump_thread.Stack.Memory.DataSize = + base::checked_cast<uint32_t>(minidump_stack.size()); minidump_thread.Stack.Memory.Rva = static_cast<RVA>(string_file.SeekGet()); EXPECT_TRUE(string_file.Write(minidump_stack.data(), minidump_stack.size())); From 131dd81d4ce4af5e85945eab344d0c2e0f8b9b87 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 5 Nov 2018 13:34:51 -0500 Subject: [PATCH 070/401] mac: Fix crashpad_snapshot_test ProcessReaderMac.Child*Thread* for 10.14 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pthread_threadid_np() reports an incorrect thread ID after fork() on macOS 10.14 (“Mojave”). See https://openradar.appspot.com/43843552. As a workaround, use thread_info(…, THREAD_IDENTIFIER_INFO, …). This uses MachThreadSelf(), which in turn uses pthread_mach_thread_np(), which does not suffer from the same bug. As an alternative, base::mac::ScopedMachSendRight(mach_thread_self()) could be used. Bug: crashpad:249 Change-Id: I757d6e94236cff533b9c1326f028110b6d214ee5 Reviewed-on: https://chromium-review.googlesource.com/c/1318271 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- snapshot/mac/process_reader_mac_test.cc | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/snapshot/mac/process_reader_mac_test.cc b/snapshot/mac/process_reader_mac_test.cc index 59884a6d..cf3604cf 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -15,6 +15,7 @@ #include "snapshot/mac/process_reader_mac.h" #include <AvailabilityMacros.h> +#include <errno.h> #include <OpenCL/opencl.h> #include <mach-o/dyld.h> #include <mach-o/dyld_images.h> @@ -26,7 +27,7 @@ #include <utility> #include "base/logging.h" -#include "base/mac/scoped_mach_port.h" +#include "base/mac/mach_logging.h" #include "base/posix/eintr_wrapper.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" @@ -127,8 +128,8 @@ TEST(ProcessReaderMac, ChildBasic) { // This function CHECKs success and returns the thread ID directly. uint64_t PthreadToThreadID(pthread_t pthread) { uint64_t thread_id; - int rv = pthread_threadid_np(pthread, &thread_id); - CHECK_EQ(rv, 0); + errno = pthread_threadid_np(pthread, &thread_id); + PCHECK(errno == 0) << "pthread_threadid_np"; return thread_id; } @@ -410,6 +411,18 @@ TEST(ProcessReaderMac, SelfSeveralThreads) { EXPECT_TRUE(found_thread_self); } +uint64_t GetThreadID() { + thread_identifier_info info; + mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT; + kern_return_t kr = thread_info(MachThreadSelf(), + THREAD_IDENTIFIER_INFO, + reinterpret_cast<thread_info_t>(&info), + &info_count); + MACH_CHECK(kr == KERN_SUCCESS, kr) << "thread_info"; + + return info.thread_id; +} + class ProcessReaderThreadedChild final : public MachMultiprocess { public: explicit ProcessReaderThreadedChild(size_t thread_count) @@ -463,7 +476,7 @@ class ProcessReaderThreadedChild final : public MachMultiprocess { // This thread isn’t part of the thread pool, but the parent will be able // to inspect it. Write an entry for it. - uint64_t thread_id = PthreadToThreadID(pthread_self()); + uint64_t thread_id = GetThreadID(); CheckedWriteFile(write_handle, &thread_id, sizeof(thread_id)); From a9be1b14037036638cc5ba6c95fd81449a388783 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Mon, 5 Nov 2018 13:14:20 -0800 Subject: [PATCH 071/401] Add ProcessMemoryWin and re-factor tests Currently, ProcessMemory is only implemented for Linux and Fuchsia. Implement the interface for Windows as well and re-factor tests to support it, mostly this consists of using a new ScopedGuardedPage class instead of ScopedMmap in the ProcessMemory tests. BUG=crashpad:262 Change-Id: I1b42718972be5ad838d12356d09f764053f09e4f Reviewed-on: https://chromium-review.googlesource.com/c/1278829 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- test/BUILD.gn | 8 +- test/scoped_guarded_page.h | 49 +++++++ test/scoped_guarded_page_posix.cc | 47 +++++++ test/scoped_guarded_page_test.cc | 35 +++++ test/scoped_guarded_page_win.cc | 39 ++++++ util/BUILD.gn | 8 +- util/process/process_memory.cc | 2 + util/process/process_memory.h | 6 + util/process/process_memory_native.h | 4 + util/process/process_memory_range.cc | 2 +- util/process/process_memory_range_test.cc | 21 +-- util/process/process_memory_test.cc | 156 ++++++---------------- util/process/process_memory_win.cc | 118 ++++++++++++++++ util/process/process_memory_win.h | 66 +++++++++ 14 files changed, 434 insertions(+), 127 deletions(-) create mode 100644 test/scoped_guarded_page.h create mode 100644 test/scoped_guarded_page_posix.cc create mode 100644 test/scoped_guarded_page_test.cc create mode 100644 test/scoped_guarded_page_win.cc create mode 100644 util/process/process_memory_win.cc create mode 100644 util/process/process_memory_win.h diff --git a/test/BUILD.gn b/test/BUILD.gn index c9630653..bded2c60 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -36,6 +36,7 @@ static_library("test") { "multiprocess_exec.h", "process_type.cc", "process_type.h", + "scoped_guarded_page.h", "scoped_module_handle.cc", "scoped_module_handle.h", "scoped_temp_dir.cc", @@ -45,7 +46,10 @@ static_library("test") { ] if (crashpad_is_posix || crashpad_is_fuchsia) { - sources += [ "scoped_temp_dir_posix.cc" ] + sources += [ + "scoped_guarded_page_posix.cc", + "scoped_temp_dir_posix.cc", + ] if (!crashpad_is_fuchsia) { sources += [ @@ -81,6 +85,7 @@ static_library("test") { if (crashpad_is_win) { sources += [ "multiprocess_exec_win.cc", + "scoped_guarded_page_win.cc", "scoped_temp_dir_win.cc", "win/child_launcher.cc", "win/child_launcher.h", @@ -144,6 +149,7 @@ source_set("test_test") { "hex_string_test.cc", "main_arguments_test.cc", "multiprocess_exec_test.cc", + "scoped_guarded_page_test.cc", "scoped_temp_dir_test.cc", "test_paths_test.cc", ] diff --git a/test/scoped_guarded_page.h b/test/scoped_guarded_page.h new file mode 100644 index 00000000..55ef2727 --- /dev/null +++ b/test/scoped_guarded_page.h @@ -0,0 +1,49 @@ +// Copyright 2018 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_GUARDED_PAGE_ +#define CRASHPAD_TEST_SCOPED_GUARDED_PAGE_ + +#include "base/macros.h" + +namespace crashpad { +namespace test { + +//! \brief A RAII object that allocates a read-write page with an inacessible +//! page following it. +//! +//! Upon construction, a mapping will be created. Failure to create the mapping +//! is fatal. On destruction, the mapping is freed. +//! +//! This object should not be used in multi-threded contexts, the POSIX +//! implementation can not be made thread-safe. +class ScopedGuardedPage { + public: + ScopedGuardedPage(); + ~ScopedGuardedPage(); + + //! \brief Returns the address of the read-write page. + //! + //! \return The address of the read-write page. + void* Pointer() const { return ptr_; } + + private: + void* ptr_; + DISALLOW_COPY_AND_ASSIGN(ScopedGuardedPage); +}; + +} // namespace test +} // namespace crashpad + +#endif // CRASHPAD_TEST_SCOPED_GUARDED_PAGE_ diff --git a/test/scoped_guarded_page_posix.cc b/test/scoped_guarded_page_posix.cc new file mode 100644 index 00000000..750fe181 --- /dev/null +++ b/test/scoped_guarded_page_posix.cc @@ -0,0 +1,47 @@ +// Copyright 2018 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_guarded_page.h" + +#include <sys/mman.h> + +#include "base/logging.h" +#include "base/process/process_metrics.h" + +namespace crashpad { +namespace test { + +ScopedGuardedPage::ScopedGuardedPage() { + ptr_ = mmap(nullptr, + base::GetPageSize() * 2, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, + 0); + PCHECK(ptr_ != MAP_FAILED) << "mmap"; + + // Simply mprotect()ing the guard page PROT_NONE does not make it inaccessible + // using ptrace() or /proc/$pid/mem so we munmap() the following page instead. + // Unfortunately, this means that the guarded page is not thread safe from + // other threads mapping a single page into the empty region. + char* second_page = static_cast<char*>(ptr_) + base::GetPageSize(); + PCHECK(munmap(second_page, base::GetPageSize()) >= 0) << "munmap"; +} + +ScopedGuardedPage::~ScopedGuardedPage() { + PCHECK(munmap(ptr_, base::GetPageSize()) >= 0) << "munmap"; +} + +} // namespace test +} // namespace crashpad diff --git a/test/scoped_guarded_page_test.cc b/test/scoped_guarded_page_test.cc new file mode 100644 index 00000000..3902ca41 --- /dev/null +++ b/test/scoped_guarded_page_test.cc @@ -0,0 +1,35 @@ +// Copyright 2018 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_guarded_page.h" + +#include "base/process/process_metrics.h" +#include "gtest/gtest.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(ScopedGuardedPage, BasicFunctionality) { + ScopedGuardedPage page; + char* address = (char*)page.Pointer(); + EXPECT_NE(address, nullptr); + address[0] = 0; + address[base::GetPageSize() - 1] = 0; + EXPECT_DEATH({ address[base::GetPageSize()] = 0; }, ""); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/test/scoped_guarded_page_win.cc b/test/scoped_guarded_page_win.cc new file mode 100644 index 00000000..23a68977 --- /dev/null +++ b/test/scoped_guarded_page_win.cc @@ -0,0 +1,39 @@ +// Copyright 2018 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_guarded_page.h" + +#include <windows.h> + +#include "base/logging.h" +#include "base/process/process_metrics.h" + +namespace crashpad { +namespace test { + +ScopedGuardedPage::ScopedGuardedPage() { + const size_t page_size = base::GetPageSize(); + ptr_ = VirtualAlloc(nullptr, page_size * 2, MEM_RESERVE, PAGE_NOACCESS); + PCHECK(ptr_ != nullptr) << "VirtualAlloc"; + + PCHECK(VirtualAlloc(ptr_, page_size, MEM_COMMIT, PAGE_READWRITE) != nullptr) + << "VirtualAlloc"; +} + +ScopedGuardedPage::~ScopedGuardedPage() { + PCHECK(VirtualFree(ptr_, 0, MEM_RELEASE)) << "VirtualFree"; +} + +} // namespace test +} // namespace crashpad diff --git a/util/BUILD.gn b/util/BUILD.gn index 0f099885..9f62e6aa 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -311,7 +311,8 @@ static_library("util") { ] } - if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) { + if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia || + crashpad_is_win) { sources += [ "process/process_memory.cc", "process/process_memory.h", @@ -332,6 +333,8 @@ static_library("util") { "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", @@ -622,7 +625,8 @@ source_set("util_test") { sources += [ "misc/capture_context_test_util_fuchsia.cc" ] } - if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) { + if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia || + crashpad_is_win) { sources += [ # TODO: Port to all platforms. "process/process_memory_range_test.cc", diff --git a/util/process/process_memory.cc b/util/process/process_memory.cc index 6bc00101..c23af93e 100644 --- a/util/process/process_memory.cc +++ b/util/process/process_memory.cc @@ -14,6 +14,8 @@ #include "util/process/process_memory.h" +#include <algorithm> + #include "base/logging.h" namespace crashpad { diff --git a/util/process/process_memory.h b/util/process/process_memory.h index d67c3828..5ea595ef 100644 --- a/util/process/process_memory.h +++ b/util/process/process_memory.h @@ -19,8 +19,14 @@ #include <string> +#include "build/build_config.h" #include "util/misc/address_types.h" +#if defined(OS_WIN) +#include <basetsd.h> +typedef SSIZE_T ssize_t; +#endif // defined(OS_WIN) + namespace crashpad { //! \brief Abstract base class for accessing the memory of another process. diff --git a/util/process/process_memory_native.h b/util/process/process_memory_native.h index 19fa805a..e81208ee 100644 --- a/util/process/process_memory_native.h +++ b/util/process/process_memory_native.h @@ -18,6 +18,8 @@ #include "util/process/process_memory_fuchsia.h" #elif defined(OS_LINUX) || defined(OS_ANDROID) #include "util/process/process_memory_linux.h" +#elif defined(OS_WIN) +#include "util/process/process_memory_win.h" #endif namespace crashpad { @@ -27,6 +29,8 @@ namespace crashpad { using ProcessMemoryNative = ProcessMemoryFuchsia; #elif defined(OS_LINUX) || defined(OS_ANDROID) using ProcessMemoryNative = ProcessMemoryLinux; +#elif defined(OS_WIN) +using ProcessMemoryNative = ProcessMemoryWin; #else #error Port. #endif diff --git a/util/process/process_memory_range.cc b/util/process/process_memory_range.cc index 32d805de..aee8c808 100644 --- a/util/process/process_memory_range.cc +++ b/util/process/process_memory_range.cc @@ -86,7 +86,7 @@ bool ProcessMemoryRange::ReadCStringSizeLimited(VMAddress address, LOG(ERROR) << "read out of range"; return false; } - size = std::min(static_cast<VMSize>(size), range_.End() - address); + size = std::min(size, base::checked_cast<size_t>(range_.End() - address)); return memory_->ReadCStringSizeLimited(address, size, string); } diff --git a/util/process/process_memory_range_test.cc b/util/process/process_memory_range_test.cc index 3784e95d..eb457c76 100644 --- a/util/process/process_memory_range_test.cc +++ b/util/process/process_memory_range_test.cc @@ -14,8 +14,6 @@ #include "util/process/process_memory_range.h" -#include <unistd.h> - #include <limits> #include "base/logging.h" @@ -27,7 +25,11 @@ #include <lib/zx/process.h> #include "util/process/process_memory_fuchsia.h" +#elif defined(OS_WIN) +#include "util/process/process_memory_win.h" #else +#include <unistd.h> + #include "util/process/process_memory_linux.h" #endif @@ -41,20 +43,21 @@ struct TestObject { } kTestObject = {"string1", "string2"}; TEST(ProcessMemoryRange, Basic) { -#if defined(OS_FUCHSIA) - ProcessMemoryFuchsia memory; - ASSERT_TRUE(memory.Initialize(*zx::process::self())); - constexpr bool is_64_bit = true; -#else - pid_t pid = getpid(); #if defined(ARCH_CPU_64_BITS) constexpr bool is_64_bit = true; #else constexpr bool is_64_bit = false; #endif // ARCH_CPU_64_BITS +#if defined(OS_FUCHSIA) + ProcessMemoryFuchsia memory; + ASSERT_TRUE(memory.Initialize(*zx::process::self())); +#elif defined(OS_WIN) + ProcessMemoryWin memory; + ASSERT_TRUE(memory.Initialize(GetCurrentProcess())); +#elif defined(OS_LINUX) ProcessMemoryLinux memory; - ASSERT_TRUE(memory.Initialize(pid)); + ASSERT_TRUE(memory.Initialize(getpid())); #endif // OS_FUCHSIA ProcessMemoryRange range; diff --git a/util/process/process_memory_test.cc b/util/process/process_memory_test.cc index 741e58d6..ca1f4973 100644 --- a/util/process/process_memory_test.cc +++ b/util/process/process_memory_test.cc @@ -15,19 +15,18 @@ #include "util/process/process_memory.h" #include <string.h> -#include <sys/mman.h> -#include <unistd.h> #include <memory> +#include "base/process/process_metrics.h" #include "gtest/gtest.h" #include "test/errors.h" #include "test/multiprocess.h" #include "test/multiprocess_exec.h" #include "test/process_type.h" +#include "test/scoped_guarded_page.h" #include "util/file/file_io.h" #include "util/misc/from_pointer_cast.h" -#include "util/posix/scoped_mmap.h" #include "util/process/process_memory_native.h" namespace crashpad { @@ -36,7 +35,7 @@ namespace { void DoChildReadTestSetup(size_t* region_size, std::unique_ptr<char[]>* region) { - *region_size = 4 * getpagesize(); + *region_size = 4 * base::GetPageSize(); region->reset(new char[*region_size]); for (size_t index = 0; index < *region_size; ++index) { (*region)[index] = index % 256; @@ -120,7 +119,7 @@ class ReadTest : public MultiprocessExec { } // Ensure that a read of exactly one page works. - size_t page_size = getpagesize(); + size_t page_size = base::GetPageSize(); ASSERT_GE(region_size, page_size + page_size); ASSERT_TRUE(memory.Read(address + page_size, page_size, result.get())); for (size_t i = 0; i < page_size; ++i) { @@ -154,7 +153,7 @@ constexpr char kConstCharShort[] = "A short const char[]"; std::string MakeLongString() { std::string long_string; - const size_t kStringLongSize = 4 * getpagesize(); + const size_t kStringLongSize = 4 * base::GetPageSize(); for (size_t index = 0; index < kStringLongSize; ++index) { long_string.push_back((index % 255) + 1); } @@ -322,101 +321,60 @@ TEST(ProcessMemory, ReadCStringSizeLimitedChild) { test.RunAgainstChild(); } -void DoReadUnmappedChildMainSetup(ScopedMmap* pages, - VMAddress* address, - size_t* page_size, - size_t* region_size) { - *page_size = getpagesize(); - *region_size = 2 * (*page_size); - if (!pages->ResetMmap(nullptr, - *region_size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, - 0)) { - ADD_FAILURE(); - return; - } - - *address = pages->addr_as<VMAddress>(); - - char* region = pages->addr_as<char*>(); - for (size_t index = 0; index < *region_size; ++index) { +void DoReadUnmappedChildMainSetup(void* page) { + char* region = reinterpret_cast<char*>(page); + for (size_t index = 0; index < base::GetPageSize(); ++index) { region[index] = index % 256; } - - EXPECT_TRUE(pages->ResetAddrLen(region, *page_size)); } CRASHPAD_CHILD_TEST_MAIN(ReadUnmappedChildMain) { - ScopedMmap pages; - VMAddress address = 0; - size_t page_size, region_size; - DoReadUnmappedChildMainSetup(&pages, &address, &page_size, ®ion_size); + ScopedGuardedPage pages; + VMAddress address = reinterpret_cast<VMAddress>(pages.Pointer()); + DoReadUnmappedChildMainSetup(pages.Pointer()); FileHandle out = StdioFileHandle(StdioStream::kStandardOutput); CheckedWriteFile(out, &address, sizeof(address)); - CheckedWriteFile(out, &page_size, sizeof(page_size)); - CheckedWriteFile(out, ®ion_size, sizeof(region_size)); CheckedReadFileAtEOF(StdioFileHandle(StdioStream::kStandardInput)); return 0; } +// This test only supports running against a child process because +// ScopedGuardedPage is not thread-safe. class ReadUnmappedTest : public MultiprocessExec { public: ReadUnmappedTest() : MultiprocessExec() { SetChildTestMainFunction("ReadUnmappedChildMain"); } - void RunAgainstSelf() { - ScopedMmap pages; - VMAddress address = 0; - size_t page_size, region_size; - DoReadUnmappedChildMainSetup(&pages, &address, &page_size, ®ion_size); - DoTest(GetSelfProcess(), address, page_size, region_size); - } - void RunAgainstChild() { Run(); } private: void MultiprocessParent() override { VMAddress address = 0; - size_t page_size, region_size; ASSERT_TRUE(ReadFileExactly(ReadPipeHandle(), &address, sizeof(address))); - ASSERT_TRUE( - ReadFileExactly(ReadPipeHandle(), &page_size, sizeof(page_size))); - ASSERT_TRUE( - ReadFileExactly(ReadPipeHandle(), ®ion_size, sizeof(region_size))); - DoTest(ChildProcess(), address, page_size, region_size); + DoTest(ChildProcess(), address); } - void DoTest(ProcessType process, - VMAddress address, - size_t page_size, - size_t region_size) { + void DoTest(ProcessType process, VMAddress address) { ProcessMemoryNative memory; ASSERT_TRUE(memory.Initialize(process)); VMAddress page_addr1 = address; - VMAddress page_addr2 = page_addr1 + page_size; + VMAddress page_addr2 = page_addr1 + base::GetPageSize(); - std::unique_ptr<char[]> result(new char[region_size]); - EXPECT_TRUE(memory.Read(page_addr1, page_size, result.get())); + std::unique_ptr<char[]> result(new char[base::GetPageSize() * 2]); + EXPECT_TRUE(memory.Read(page_addr1, base::GetPageSize(), result.get())); EXPECT_TRUE(memory.Read(page_addr2 - 1, 1, result.get())); - EXPECT_FALSE(memory.Read(page_addr1, region_size, result.get())); - EXPECT_FALSE(memory.Read(page_addr2, page_size, result.get())); + EXPECT_FALSE( + memory.Read(page_addr1, base::GetPageSize() * 2, result.get())); + EXPECT_FALSE(memory.Read(page_addr2, base::GetPageSize(), result.get())); EXPECT_FALSE(memory.Read(page_addr2 - 1, 2, result.get())); } DISALLOW_COPY_AND_ASSIGN(ReadUnmappedTest); }; -TEST(ProcessMemory, ReadUnmappedSelf) { - ReadUnmappedTest test; - ASSERT_FALSE(testing::Test::HasFailure()); - test.RunAgainstSelf(); -} - TEST(ProcessMemory, ReadUnmappedChild) { ReadUnmappedTest test; ASSERT_FALSE(testing::Test::HasFailure()); @@ -428,9 +386,13 @@ constexpr size_t kChildProcessStringLength = 10; class StringDataInChildProcess { public: // This constructor only makes sense in the child process. - explicit StringDataInChildProcess(const char* cstring) + explicit StringDataInChildProcess(const char* cstring, bool valid) : address_(FromPointerCast<VMAddress>(cstring)) { - memcpy(expected_value_, cstring, kChildProcessStringLength + 1); + if (valid) { + memcpy(expected_value_, cstring, kChildProcessStringLength + 1); + } else { + memset(expected_value_, 0xff, kChildProcessStringLength + 1); + } } void Write(FileHandle out) { @@ -457,22 +419,10 @@ class StringDataInChildProcess { }; void DoCStringUnmappedTestSetup( - ScopedMmap* pages, + void* page, std::vector<StringDataInChildProcess>* strings) { - const size_t page_size = getpagesize(); - const size_t region_size = 2 * page_size; - if (!pages->ResetMmap(nullptr, - region_size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, - 0)) { - ADD_FAILURE(); - return; - } - - char* region = pages->addr_as<char*>(); - for (size_t index = 0; index < region_size; ++index) { + char* region = reinterpret_cast<char*>(page); + for (size_t index = 0; index < base::GetPageSize(); ++index) { region[index] = 1 + index % 255; } @@ -481,29 +431,25 @@ void DoCStringUnmappedTestSetup( string1[kChildProcessStringLength] = '\0'; // A string near the end of the mapped region - char* string2 = region + page_size - kChildProcessStringLength * 2; + char* string2 = region + base::GetPageSize() - kChildProcessStringLength * 2; string2[kChildProcessStringLength] = '\0'; // A string that crosses from the mapped into the unmapped region - char* string3 = region + page_size - kChildProcessStringLength + 1; - string3[kChildProcessStringLength] = '\0'; + char* string3 = region + base::GetPageSize() - kChildProcessStringLength + 1; // A string entirely in the unmapped region - char* string4 = region + page_size + 10; - string4[kChildProcessStringLength] = '\0'; + char* string4 = region + base::GetPageSize() + 10; - strings->push_back(StringDataInChildProcess(string1)); - strings->push_back(StringDataInChildProcess(string2)); - strings->push_back(StringDataInChildProcess(string3)); - strings->push_back(StringDataInChildProcess(string4)); - - EXPECT_TRUE(pages->ResetAddrLen(region, page_size)); + strings->push_back(StringDataInChildProcess(string1, true)); + strings->push_back(StringDataInChildProcess(string2, true)); + strings->push_back(StringDataInChildProcess(string3, false)); + strings->push_back(StringDataInChildProcess(string4, false)); } CRASHPAD_CHILD_TEST_MAIN(ReadCStringUnmappedChildMain) { - ScopedMmap pages; + ScopedGuardedPage pages; std::vector<StringDataInChildProcess> strings; - DoCStringUnmappedTestSetup(&pages, &strings); + DoCStringUnmappedTestSetup(pages.Pointer(), &strings); FileHandle out = StdioFileHandle(StdioStream::kStandardOutput); strings[0].Write(out); strings[1].Write(out); @@ -513,6 +459,8 @@ CRASHPAD_CHILD_TEST_MAIN(ReadCStringUnmappedChildMain) { return 0; } +// This test only supports running against a child process because +// ScopedGuardedPage is not thread-safe. class ReadCStringUnmappedTest : public MultiprocessExec { public: ReadCStringUnmappedTest(bool limit_size) @@ -520,13 +468,6 @@ class ReadCStringUnmappedTest : public MultiprocessExec { SetChildTestMainFunction("ReadCStringUnmappedChildMain"); } - void RunAgainstSelf() { - ScopedMmap pages; - std::vector<StringDataInChildProcess> strings; - DoCStringUnmappedTestSetup(&pages, &strings); - DoTest(GetSelfProcess(), strings); - } - void RunAgainstChild() { Run(); } private: @@ -536,8 +477,7 @@ class ReadCStringUnmappedTest : public MultiprocessExec { strings.push_back(StringDataInChildProcess::Read(ReadPipeHandle())); strings.push_back(StringDataInChildProcess::Read(ReadPipeHandle())); strings.push_back(StringDataInChildProcess::Read(ReadPipeHandle())); - ASSERT_NO_FATAL_FAILURE(); - DoTest(ChildProcess(), strings); + ASSERT_NO_FATAL_FAILURE(DoTest(ChildProcess(), strings)); } void DoTest(ProcessType process, @@ -574,24 +514,12 @@ class ReadCStringUnmappedTest : public MultiprocessExec { DISALLOW_COPY_AND_ASSIGN(ReadCStringUnmappedTest); }; -TEST(ProcessMemory, ReadCStringUnmappedSelf) { - ReadCStringUnmappedTest test(/* limit_size= */ false); - ASSERT_FALSE(testing::Test::HasFailure()); - test.RunAgainstSelf(); -} - TEST(ProcessMemory, ReadCStringUnmappedChild) { ReadCStringUnmappedTest test(/* limit_size= */ false); ASSERT_FALSE(testing::Test::HasFailure()); test.RunAgainstChild(); } -TEST(ProcessMemory, ReadCStringSizeLimitedUnmappedSelf) { - ReadCStringUnmappedTest test(/* limit_size= */ true); - ASSERT_FALSE(testing::Test::HasFailure()); - test.RunAgainstSelf(); -} - TEST(ProcessMemory, ReadCStringSizeLimitedUnmappedChild) { ReadCStringUnmappedTest test(/* limit_size= */ true); ASSERT_FALSE(testing::Test::HasFailure()); diff --git a/util/process/process_memory_win.cc b/util/process/process_memory_win.cc new file mode 100644 index 00000000..d61e7c5e --- /dev/null +++ b/util/process/process_memory_win.cc @@ -0,0 +1,118 @@ +// Copyright 2018 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/process/process_memory_win.h" + +#include <windows.h> + +#include <algorithm> +#include <limits> + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" +#include "base/process/process_metrics.h" +#include "base/strings/stringprintf.h" + +namespace crashpad { + +ProcessMemoryWin::ProcessMemoryWin() + : ProcessMemory(), handle_(), process_info_(), initialized_() {} + +ProcessMemoryWin::~ProcessMemoryWin() {} + +bool ProcessMemoryWin::Initialize(HANDLE handle) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + handle_ = handle; + if (!process_info_.Initialize(handle)) { + LOG(ERROR) << "Failed to initialize ProcessInfo."; + return false; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +ssize_t ProcessMemoryWin::ReadUpTo(VMAddress address, + size_t size, + void* buffer) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + DCHECK_LE(size, (size_t)std::numeric_limits<ssize_t>::max()); + + SIZE_T size_out = 0; + BOOL success = ReadProcessMemory( + handle_, reinterpret_cast<void*>(address), buffer, size, &size_out); + if (success) + return base::checked_cast<ssize_t>(size_out); + + if (GetLastError() == ERROR_PARTIAL_COPY) { + // If we can not read the entire section, perform a short read of the first + // page instead. This is necessary to support ReadCString(). + size_t short_read = + base::GetPageSize() - (address & (base::GetPageSize() - 1)); + success = ReadProcessMemory(handle_, + reinterpret_cast<void*>(address), + buffer, + short_read, + &size_out); + if (success) + return base::checked_cast<ssize_t>(size_out); + } + + PLOG(ERROR) << "ReadMemory at 0x" << std::hex << address << std::dec << " of " + << size << " bytes failed"; + return -1; +} + +size_t ProcessMemoryWin::ReadAvailableMemory(VMAddress address, + size_t size, + void* buffer) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + DCHECK_LE(size, (size_t)std::numeric_limits<ssize_t>::max()); + + if (size == 0) + return 0; + + auto ranges = process_info_.GetReadableRanges( + CheckedRange<WinVMAddress, WinVMSize>(address, size)); + + // We only read up until the first unavailable byte, so we only read from the + // first range. If we have no ranges, then no bytes were accessible anywhere + // in the range. + if (ranges.empty()) { + LOG(ERROR) << base::StringPrintf( + "range at 0x%llx, size 0x%llx completely inaccessible", address, size); + return 0; + } + + // If the start address was adjusted, we couldn't read even the first + // requested byte. + if (ranges.front().base() != address) { + LOG(ERROR) << base::StringPrintf( + "start of range at 0x%llx, size 0x%llx inaccessible", address, size); + return 0; + } + + DCHECK_LE(ranges.front().size(), size); + + ssize_t result = ReadUpTo(ranges.front().base(), + base::checked_cast<size_t>(ranges.front().size()), + buffer); + if (result < 0) + return 0; + + return base::checked_cast<size_t>(result); +} + +} // namespace crashpad diff --git a/util/process/process_memory_win.h b/util/process/process_memory_win.h new file mode 100644 index 00000000..2856900e --- /dev/null +++ b/util/process/process_memory_win.h @@ -0,0 +1,66 @@ +// Copyright 2018 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_PROCESS_PROCESS_MEMORY_WIN_H_ +#define CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_WIN_H_ + +#include <windows.h> + +#include "base/macros.h" +#include "util/misc/address_types.h" +#include "util/misc/initialization_state_dcheck.h" +#include "util/process/process_memory.h" +#include "util/win/process_info.h" + +namespace crashpad { + +//! \brief Accesses the memory of another Windows process. +class ProcessMemoryWin final : public ProcessMemory { + public: + ProcessMemoryWin(); + ~ProcessMemoryWin(); + + //! \brief Initializes this object to read the memory of a process with the + //! provided handle. + //! + //! This method must be called successfully prior to calling any other method + //! in this class. + //! + //! \param[in] handle The HANDLE of a target process. + //! + //! \return `true` on success, `false` on failure with a message logged. + bool Initialize(HANDLE handle); + + //! \brief Attempts to read \a size bytes from the target process starting at + //! address \a address into \a buffer. If some of the specified range is + //! not accessible, reads up to the first inaccessible byte. + //! + //! \return The actual number of bytes read. + size_t ReadAvailableMemory(VMAddress address, + size_t num_bytes, + void* buffer) const; + + private: + ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) const override; + + HANDLE handle_; + ProcessInfo process_info_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ProcessMemoryWin); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_WIN_H_ From 7f71c57a29cd9cfa719eb7730d8984aaef4adc05 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Mon, 5 Nov 2018 14:56:19 -0800 Subject: [PATCH 072/401] [fuchsia] re-introduce pstate temporarily https://fuchsia.googlesource.com/garnet/+/master/bin/zxdb/client/minidump_remote_api.cc#127 still depends on pstate and we cannot run CQ for hard transitions in Fuchsia yet Change-Id: Iea2bfc670871a8fe3f389cc54627733e6069ecbe Reviewed-on: https://chromium-review.googlesource.com/c/1318067 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- snapshot/cpu_context.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/snapshot/cpu_context.h b/snapshot/cpu_context.h index fb23c467..f1ce503f 100644 --- a/snapshot/cpu_context.h +++ b/snapshot/cpu_context.h @@ -299,7 +299,12 @@ struct CPUContextARM64 { uint64_t regs[31]; uint64_t sp; uint64_t pc; - uint32_t spsr; + // TODO(frousseau): remove pstate once clients have transitioned to spsr, + // notably zxdb in Fuchsia. + union { + uint32_t spsr; + uint64_t pstate; + }; uint128_struct fpsimd[32]; uint32_t fpsr; From fdfd782c9bd6a3f53ce5108d7d5090b85ca91f75 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Mon, 5 Nov 2018 16:49:13 -0800 Subject: [PATCH 073/401] switch to EXPECT_DEATH_CRASH * introduced in https://chromium-review.googlesource.com/c/1278829 * this blocks the rollup in Fuchsia: ../../third_party/crashpad/test/scoped_guarded_page_test.cc:30:3: error: use of undeclared identifier 'EXPECT_DEATH' Bug: crashpad:262 Change-Id: Ifff85a63aba012533956ce494fc645b554761478 Reviewed-on: https://chromium-review.googlesource.com/c/1318313 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- test/scoped_guarded_page_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/scoped_guarded_page_test.cc b/test/scoped_guarded_page_test.cc index 3902ca41..00fba7ef 100644 --- a/test/scoped_guarded_page_test.cc +++ b/test/scoped_guarded_page_test.cc @@ -16,6 +16,7 @@ #include "base/process/process_metrics.h" #include "gtest/gtest.h" +#include "test/gtest_death.h" namespace crashpad { namespace test { @@ -27,7 +28,7 @@ TEST(ScopedGuardedPage, BasicFunctionality) { EXPECT_NE(address, nullptr); address[0] = 0; address[base::GetPageSize() - 1] = 0; - EXPECT_DEATH({ address[base::GetPageSize()] = 0; }, ""); + EXPECT_DEATH_CRASH({ address[base::GetPageSize()] = 0; }, ""); } } // namespace From bf10ed0a693b4c2b4414ab0299aeb084fb6003c1 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 6 Nov 2018 12:54:37 -0800 Subject: [PATCH 074/401] posix: use threadsafe gtest death test for ScopedGuardedPage Also update gyp to build it. Change-Id: I859c552b9cfc41f531ffb04fe6d6730dbd0e8fed Reviewed-on: https://chromium-review.googlesource.com/c/1319269 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- test/scoped_guarded_page_test.cc | 2 ++ test/test.gyp | 2 ++ test/test_test.gyp | 1 + util/process/process_memory_range_test.cc | 2 +- 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/scoped_guarded_page_test.cc b/test/scoped_guarded_page_test.cc index 00fba7ef..023d1ed1 100644 --- a/test/scoped_guarded_page_test.cc +++ b/test/scoped_guarded_page_test.cc @@ -23,6 +23,8 @@ namespace test { namespace { TEST(ScopedGuardedPage, BasicFunctionality) { + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + ScopedGuardedPage page; char* address = (char*)page.Pointer(); EXPECT_NE(address, nullptr); diff --git a/test/test.gyp b/test/test.gyp index 29737088..8101f8f2 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -63,6 +63,8 @@ 'multiprocess_posix.cc', 'process_type.cc', 'process_type.h', + 'scoped_guarded_page.h', + 'scoped_guarded_page_posix.cc', 'scoped_module_handle.cc', 'scoped_module_handle.h', 'scoped_temp_dir.cc', diff --git a/test/test_test.gyp b/test/test_test.gyp index 3c6d7066..ddd920e9 100644 --- a/test/test_test.gyp +++ b/test/test_test.gyp @@ -39,6 +39,7 @@ 'main_arguments_test.cc', 'multiprocess_exec_test.cc', 'multiprocess_posix_test.cc', + 'scoped_guarded_page_test.cc', 'scoped_temp_dir_test.cc', 'test_paths_test.cc', 'win/win_child_process_test.cc', diff --git a/util/process/process_memory_range_test.cc b/util/process/process_memory_range_test.cc index eb457c76..19de2b10 100644 --- a/util/process/process_memory_range_test.cc +++ b/util/process/process_memory_range_test.cc @@ -55,7 +55,7 @@ TEST(ProcessMemoryRange, Basic) { #elif defined(OS_WIN) ProcessMemoryWin memory; ASSERT_TRUE(memory.Initialize(GetCurrentProcess())); -#elif defined(OS_LINUX) +#elif defined(OS_LINUX) || defined(OS_ANDROID) ProcessMemoryLinux memory; ASSERT_TRUE(memory.Initialize(getpid())); #endif // OS_FUCHSIA From 3663b7cbbec594fbfc23e5e5fcb23154e078f83d Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 6 Nov 2018 13:19:06 -0800 Subject: [PATCH 075/401] Reland "Use a relative address in .note.crashpad.info" This is a reland of 95e97a32eba4d505ab9591e683d2147c441eea48 Original change's description: > Use a relative address in .note.crashpad.info > > The desc value in the note is now the offset of CRASHPAD_INFO_SYMBOL > from desc. > > Making this note writable can trigger a linker error resulting in > the binary embedding .note.crashpad.info to be rejected by the > kernel during program loading. > > The error was observed with: > GNU ld (GNU Binutils for Debian) 2.30 > clang version 4.0.1-10 (tags/RELEASE_401/final) > Debian 4.17.17-1rodete2 > > When the note is made writable, crashpad_snapshot_test contains two > PT_LOAD segments which map to the same page. > > LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 > 0x0000000000000258 0x0000000000000258 R 0x200000 > LOAD 0x0000000000000258 0x0000000000000258 0x0000000000000258 > 0x00000000002b84d8 0x00000000002b8950 RWE 0x200000 > > Executing this binary with the execv system call triggers a segfault > during program loading (an error can't be returned because the original > process vm has already been discarded). > > I suspect (I haven't set up a debuggable kernel) the failure occurs > while attempting to map the second load segment because its virtual > address, 0x258, is in the same page as the first load segment. > https://elixir.bootlin.com/linux/v4.17.17/source/fs/binfmt_elf.c#L380 > > The linker normally produces consecutive load segments where the second > segment is loaded 0x200000 bytes after the first, which I think is the > maximum expected page size. Modifying the test executable to load the > second segment at 0x1258 (4096 byte page size) allows program loading > to succeed (but of course crashes after control is given to it). > > Bug: crashpad:260 > Change-Id: I2b9f1e66e98919138baef3da991a9710bd970dc4 > Reviewed-on: https://chromium-review.googlesource.com/c/1292232 > Reviewed-by: Scott Graham <scottmg@chromium.org> > Reviewed-by: Mark Mentovai <mark@chromium.org> > Commit-Queue: Joshua Peraza <jperaza@chromium.org> Bug: crashpad:260 Change-Id: I66713de84cc26c9119e0454d19c9c189263fe054 Reviewed-on: https://chromium-review.googlesource.com/c/1318066 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- client/crashpad_info_note.S | 44 +++++++++++++++---------- snapshot/crashpad_info_size_test_note.S | 18 ++++------ snapshot/elf/elf_image_reader.cc | 12 ++++--- snapshot/elf/elf_image_reader.h | 16 ++++++--- snapshot/elf/elf_image_reader_fuzzer.cc | 4 ++- snapshot/elf/elf_image_reader_test.cc | 10 +++--- snapshot/elf/module_snapshot_elf.cc | 15 +++++++-- 7 files changed, 74 insertions(+), 45 deletions(-) diff --git a/client/crashpad_info_note.S b/client/crashpad_info_note.S index 4c29298d..b13d8642 100644 --- a/client/crashpad_info_note.S +++ b/client/crashpad_info_note.S @@ -26,16 +26,13 @@ #define NOTE_ALIGN 4 // This section must be "a"llocated so that it appears in the final binary at - // runtime, and "w"ritable so that the relocation to CRASHPAD_INFO_SYMBOL can - // be performed. - .section .note.crashpad.info,"aw",%note + // runtime. The reference to CRASHPAD_INFO_SYMBOL uses an offset relative to + // this note to avoid making this note writable, which triggers a bug in GNU + // ld, or adding text relocations which require the target system to allow + // making text segments writable. https://crbug.com/crashpad/260. + .section .note.crashpad.info,"a",%note .balign NOTE_ALIGN - # .globl indicates that it's available to link against other .o files. .hidden - # indicates that it will not appear in the executable's symbol table. - .globl CRASHPAD_NOTE_REFERENCE - .hidden CRASHPAD_NOTE_REFERENCE - .type CRASHPAD_NOTE_REFERENCE, %object -CRASHPAD_NOTE_REFERENCE: +CRASHPAD_NOTE: .long name_end - name // namesz .long desc_end - desc // descsz .long CRASHPAD_ELF_NOTE_TYPE_CRASHPAD_INFO // type @@ -45,15 +42,26 @@ name_end: .balign NOTE_ALIGN desc: #if defined(__LP64__) - .quad CRASHPAD_INFO_SYMBOL + .quad CRASHPAD_INFO_SYMBOL - desc #else -#if defined(__LITTLE_ENDIAN__) - .long CRASHPAD_INFO_SYMBOL - .long 0 -#else - .long 0 - .long CRASHPAD_INFO_SYMBOL -#endif // __LITTLE_ENDIAN__ + .long CRASHPAD_INFO_SYMBOL - desc #endif // __LP64__ desc_end: - .size CRASHPAD_NOTE_REFERENCE, .-CRASHPAD_NOTE_REFERENCE + .size CRASHPAD_NOTE, .-CRASHPAD_NOTE + + // CRASHPAD_NOTE can't be referenced directly by GetCrashpadInfo() because the + // relocation used to make the reference may require that the address be + // 8-byte aligned and notes must have 4-byte alignment. + .section .rodata,"a",%progbits + .balign 8 + # .globl indicates that it's available to link against other .o files. .hidden + # indicates that it will not appear in the executable's symbol table. + .globl CRASHPAD_NOTE_REFERENCE + .hidden CRASHPAD_NOTE_REFERENCE + .type CRASHPAD_NOTE_REFERENCE, %object +CRASHPAD_NOTE_REFERENCE: + // The value of this quad isn't important. It exists to reference + // CRASHPAD_NOTE, causing the linker to include the note into the binary + // linking Crashpad. The subtraction from |name| is a convenience to allow the + // value to be computed statically. + .quad name - CRASHPAD_NOTE diff --git a/snapshot/crashpad_info_size_test_note.S b/snapshot/crashpad_info_size_test_note.S index 96b996db..16b5d499 100644 --- a/snapshot/crashpad_info_size_test_note.S +++ b/snapshot/crashpad_info_size_test_note.S @@ -26,9 +26,11 @@ #define NOTE_ALIGN 4 // This section must be "a"llocated so that it appears in the final binary at - // runtime, and "w"ritable so that the relocation to TEST_CRASHPAD_INFO_SYMBOL - // can be performed. - .section .note.crashpad.info,"aw",%note + // runtime. The reference to TEST_CRASHPAD_INFO_SYMBOL uses an offset relative + // to this note to avoid making this note writable, which triggers a bug in + // GNU ld, or adding text relocations which require the target system to allow + // making text segments writable. https://crbug.com/crashpad/260. + .section .note.crashpad.info,"a",%note .balign NOTE_ALIGN .type info_size_test_note, %object info_size_test_note: @@ -41,15 +43,9 @@ name_end: .balign NOTE_ALIGN desc: #if defined(__LP64__) - .quad TEST_CRASHPAD_INFO_SYMBOL + .quad TEST_CRASHPAD_INFO_SYMBOL - desc #else -#if defined(__LITTLE_ENDIAN__) - .long TEST_CRASHPAD_INFO_SYMBOL - .long 0 -#else - .long 0 - .long TEST_CRASHPAD_INFO_SYMBOL -#endif // __LITTLE_ENDIAN__ + .long TEST_CRASHPAD_INFO_SYMBOL - desc #endif // __LP64__ desc_end: .size info_size_test_note, .-info_size_test_note diff --git a/snapshot/elf/elf_image_reader.cc b/snapshot/elf/elf_image_reader.cc index 8ee51d34..ffe3f7b1 100644 --- a/snapshot/elf/elf_image_reader.cc +++ b/snapshot/elf/elf_image_reader.cc @@ -191,7 +191,8 @@ ElfImageReader::NoteReader::~NoteReader() = default; ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::NextNote( std::string* name, NoteType* type, - std::string* desc) { + std::string* desc, + VMAddress* desc_address) { if (!is_valid_) { LOG(ERROR) << "invalid note reader"; return Result::kError; @@ -215,8 +216,9 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::NextNote( } retry_ = false; - result = range_->Is64Bit() ? ReadNote<Elf64_Nhdr>(name, type, desc) - : ReadNote<Elf32_Nhdr>(name, type, desc); + result = range_->Is64Bit() + ? ReadNote<Elf64_Nhdr>(name, type, desc, desc_address) + : ReadNote<Elf32_Nhdr>(name, type, desc, desc_address); } while (retry_); if (result == Result::kSuccess) { @@ -251,7 +253,8 @@ template <typename NhdrType> ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( std::string* name, NoteType* type, - std::string* desc) { + std::string* desc, + VMAddress* desc_address) { static_assert(sizeof(*type) >= sizeof(NhdrType::n_namesz), "Note field size mismatch"); DCHECK_LT(current_address_, segment_end_address_); @@ -317,6 +320,7 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( current_address_, note_info.n_descsz, &local_desc[0])) { return Result::kError; } + *desc_address = current_address_; current_address_ = end_of_note; diff --git a/snapshot/elf/elf_image_reader.h b/snapshot/elf/elf_image_reader.h index 317b35ad..f35c7616 100644 --- a/snapshot/elf/elf_image_reader.h +++ b/snapshot/elf/elf_image_reader.h @@ -70,9 +70,14 @@ class ElfImageReader { //! \param[out] name The name of the note owner, if not `nullptr`. //! \param[out] type A type for the note, if not `nullptr`. //! \param[out] desc The note descriptor. - //! \return a #Result value. \a name, \a type, and \a desc are only valid if - //! this method returns Result::kSuccess. - Result NextNote(std::string* name, NoteType* type, std::string* desc); + //! \param[out] desc_addr The address in the remote process' address space + //! \a desc was read from. + //! \return a #Result value. \a name, \a type, \a desc, and \a desc_addr are + //! only valid if this method returns Result::kSuccess. + Result NextNote(std::string* name, + NoteType* type, + std::string* desc, + VMAddress* desc_addr); // private NoteReader(const ElfImageReader* elf_reader_, @@ -88,7 +93,10 @@ class ElfImageReader { // and returns kError if use_filter_ is true and the note's name and type do // not match name_filter_ and type_filter_. template <typename T> - Result ReadNote(std::string* name, NoteType* type, std::string* desc); + Result ReadNote(std::string* name, + NoteType* type, + std::string* desc, + VMAddress* desc_addr); VMAddress current_address_; VMAddress segment_end_address_; diff --git a/snapshot/elf/elf_image_reader_fuzzer.cc b/snapshot/elf/elf_image_reader_fuzzer.cc index 1686650b..73bded72 100644 --- a/snapshot/elf/elf_image_reader_fuzzer.cc +++ b/snapshot/elf/elf_image_reader_fuzzer.cc @@ -65,8 +65,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { std::string note_name; std::string note_desc; ElfImageReader::NoteReader::NoteType note_type; + VMAddress desc_addr; auto notes = reader.Notes(-1); - while ((result = notes->NextNote(¬e_name, ¬e_type, ¬e_desc)) == + while ((result = notes->NextNote( + ¬e_name, ¬e_type, ¬e_desc, &desc_addr)) == ElfImageReader::NoteReader::Result::kSuccess) { LOG(ERROR) << note_name << note_type << note_desc; } diff --git a/snapshot/elf/elf_image_reader_test.cc b/snapshot/elf/elf_image_reader_test.cc index 6d88d817..2cc0faa5 100644 --- a/snapshot/elf/elf_image_reader_test.cc +++ b/snapshot/elf/elf_image_reader_test.cc @@ -154,22 +154,24 @@ void ReadThisExecutableInTarget(ProcessType process, std::string note_name; std::string note_desc; ElfImageReader::NoteReader::NoteType note_type; + VMAddress desc_addr; std::unique_ptr<ElfImageReader::NoteReader> notes = reader.Notes(-1); - while ((result = notes->NextNote(¬e_name, ¬e_type, ¬e_desc)) == + while ((result = notes->NextNote( + ¬e_name, ¬e_type, ¬e_desc, &desc_addr)) == ElfImageReader::NoteReader::Result::kSuccess) { } EXPECT_EQ(result, ElfImageReader::NoteReader::Result::kNoMoreNotes); notes = reader.Notes(0); - EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc), + EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), ElfImageReader::NoteReader::Result::kNoMoreNotes); // Find the note defined in elf_image_reader_test_note.S. constexpr uint32_t kCrashpadNoteDesc = 42; notes = reader.NotesWithNameAndType( CRASHPAD_ELF_NOTE_NAME, CRASHPAD_ELF_NOTE_TYPE_SNAPSHOT_TEST, -1); - ASSERT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc), + ASSERT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), ElfImageReader::NoteReader::Result::kSuccess); EXPECT_EQ(note_name, CRASHPAD_ELF_NOTE_NAME); EXPECT_EQ(note_type, @@ -178,7 +180,7 @@ void ReadThisExecutableInTarget(ProcessType process, EXPECT_EQ(*reinterpret_cast<decltype(kCrashpadNoteDesc)*>(¬e_desc[0]), kCrashpadNoteDesc); - EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc), + EXPECT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), ElfImageReader::NoteReader::Result::kNoMoreNotes); } diff --git a/snapshot/elf/module_snapshot_elf.cc b/snapshot/elf/module_snapshot_elf.cc index 62a961d3..39385a6d 100644 --- a/snapshot/elf/module_snapshot_elf.cc +++ b/snapshot/elf/module_snapshot_elf.cc @@ -56,9 +56,17 @@ bool ModuleSnapshotElf::Initialize() { kMaxNoteSize); std::string desc; VMAddress info_address; - if (notes->NextNote(nullptr, nullptr, &desc) == + VMAddress desc_address; + if (notes->NextNote(nullptr, nullptr, &desc, &desc_address) == ElfImageReader::NoteReader::Result::kSuccess) { - info_address = *reinterpret_cast<VMAddress*>(&desc[0]); + VMOffset offset; + if (elf_reader_->Memory()->Is64Bit()) { + offset = *reinterpret_cast<VMOffset*>(&desc[0]); + } else { + int32_t offset32 = *reinterpret_cast<int32_t*>(&desc[0]); + offset = offset32; + } + info_address = desc_address + offset; ProcessMemoryRange range; if (range.Initialize(*elf_reader_->Memory())) { @@ -145,7 +153,8 @@ void ModuleSnapshotElf::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const { std::unique_ptr<ElfImageReader::NoteReader> notes = elf_reader_->NotesWithNameAndType(ELF_NOTE_GNU, NT_GNU_BUILD_ID, 64); std::string desc; - notes->NextNote(nullptr, nullptr, &desc); + VMAddress desc_addr; + notes->NextNote(nullptr, nullptr, &desc, &desc_addr); desc.insert(desc.end(), 16 - std::min(desc.size(), size_t{16}), '\0'); uuid->InitializeFromBytes(reinterpret_cast<const uint8_t*>(&desc[0])); From 71c75401c43c771bbdf18329b92477914cc6afa2 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 6 Nov 2018 22:11:43 +0000 Subject: [PATCH 076/401] Revert "[fuchsia] re-introduce pstate temporarily" This reverts commit 7f71c57a29cd9cfa719eb7730d8984aaef4adc05. Reason for revert: Fuchsia has been transitioned to spsr. Original change's description: > [fuchsia] re-introduce pstate temporarily > > https://fuchsia.googlesource.com/garnet/+/master/bin/zxdb/client/minidump_remote_api.cc#127 > still depends on pstate and we cannot run CQ for hard transitions in Fuchsia yet > > Change-Id: Iea2bfc670871a8fe3f389cc54627733e6069ecbe > Reviewed-on: https://chromium-review.googlesource.com/c/1318067 > Reviewed-by: Scott Graham <scottmg@chromium.org> > Commit-Queue: Francois Rousseau <frousseau@google.com> TBR=scottmg@chromium.org,frousseau@google.com Change-Id: I5a13cab9a11b6c1262d6832e2dd5b09cad5b3740 No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/c/1321269 Reviewed-by: Francois Rousseau <frousseau@google.com> Commit-Queue: Francois Rousseau <frousseau@google.com> --- snapshot/cpu_context.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/snapshot/cpu_context.h b/snapshot/cpu_context.h index f1ce503f..fb23c467 100644 --- a/snapshot/cpu_context.h +++ b/snapshot/cpu_context.h @@ -299,12 +299,7 @@ struct CPUContextARM64 { uint64_t regs[31]; uint64_t sp; uint64_t pc; - // TODO(frousseau): remove pstate once clients have transitioned to spsr, - // notably zxdb in Fuchsia. - union { - uint32_t spsr; - uint64_t pstate; - }; + uint32_t spsr; uint128_struct fpsimd[32]; uint32_t fpsr; From e287a3ab12afe5ca070608278d893d481bb964e4 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 7 Nov 2018 10:18:29 -0800 Subject: [PATCH 077/401] win: fix mismatched format macros When building in Chromium: ../../third_party/crashpad/crashpad/util/process/process_memory_win.cc(95,74): error: format specifies type 'unsigned long long' but the argument has type 'size_t' (aka 'unsigned int') [-Werror,-Wformat] "range at 0x%llx, size 0x%llx completely inaccessible", address, size); ~~~~ ^~~~ %zx ../../third_party/crashpad/crashpad/util/process/process_memory_win.cc(103,72): error: format specifies type 'unsigned long long' but the argument has type 'size_t' (aka 'unsigned int') [-Werror,-Wformat] "start of range at 0x%llx, size 0x%llx inaccessible", address, size); Change-Id: I820f0afee28d1220ca400780eac61de05bde10ef Reviewed-on: https://chromium-review.googlesource.com/c/1323771 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/process/process_memory_win.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/util/process/process_memory_win.cc b/util/process/process_memory_win.cc index d61e7c5e..5303d709 100644 --- a/util/process/process_memory_win.cc +++ b/util/process/process_memory_win.cc @@ -92,7 +92,9 @@ size_t ProcessMemoryWin::ReadAvailableMemory(VMAddress address, // in the range. if (ranges.empty()) { LOG(ERROR) << base::StringPrintf( - "range at 0x%llx, size 0x%llx completely inaccessible", address, size); + "range at 0x%llx, size 0x%llx completely inaccessible", + address, + WinVMSize{size}); return 0; } @@ -100,7 +102,9 @@ size_t ProcessMemoryWin::ReadAvailableMemory(VMAddress address, // requested byte. if (ranges.front().base() != address) { LOG(ERROR) << base::StringPrintf( - "start of range at 0x%llx, size 0x%llx inaccessible", address, size); + "start of range at 0x%llx, size 0x%llx inaccessible", + address, + WinVMSize{size}); return 0; } From 651af7583b35a4d8fd2b645b5b640e328d88ef88 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 7 Nov 2018 10:58:51 -0800 Subject: [PATCH 078/401] win: use zx format specifier instead of a cast Change-Id: I14fac035ecafaa5d2459b63a070f701389160ad4 Reviewed-on: https://chromium-review.googlesource.com/c/1323772 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/process/process_memory_win.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/util/process/process_memory_win.cc b/util/process/process_memory_win.cc index 5303d709..f716102b 100644 --- a/util/process/process_memory_win.cc +++ b/util/process/process_memory_win.cc @@ -92,9 +92,7 @@ size_t ProcessMemoryWin::ReadAvailableMemory(VMAddress address, // in the range. if (ranges.empty()) { LOG(ERROR) << base::StringPrintf( - "range at 0x%llx, size 0x%llx completely inaccessible", - address, - WinVMSize{size}); + "range at 0x%llx, size 0x%zx completely inaccessible", address, size); return 0; } @@ -102,9 +100,7 @@ size_t ProcessMemoryWin::ReadAvailableMemory(VMAddress address, // requested byte. if (ranges.front().base() != address) { LOG(ERROR) << base::StringPrintf( - "start of range at 0x%llx, size 0x%llx inaccessible", - address, - WinVMSize{size}); + "start of range at 0x%llx, size 0x%zx inaccessible", address, size); return 0; } From fdc1883a13ac41656a3fb34ce172cbc85d63d46e Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 8 Nov 2018 17:02:20 -0800 Subject: [PATCH 079/401] fuchsia: Disable ProcessReaderFuchsia.ChildThreads, flaking Flaking like: [ RUN ] ProcessReaderFuchsia.ChildThreads [22244:22258:20181109,001621.809627:ERROR scoped_task_suspend.cc:44] thread failed to suspend [22244:22258:20181109,001621.810893:WARNING process_reader_fuchsia.cc:283] zx_thread_read_state(ZX_THREAD_STATE_GENERAL_REGS): ZX_ERR_BAD_STATE (-20) [22244:22258:20181109,001621.810937:WARNING process_reader_fuchsia.cc:295] zx_thread_read_state(ZX_THREAD_STATE_VECTOR_REGS): ZX_ERR_BAD_STATE (-20) ../../third_party/crashpad/snapshot/fuchsia/process_reader_fuchsia_test.cc:161: Failure Expected: (threads[i].stack_regions.size()) > (0u), actual: 0 vs 0 [ FAILED ] ProcessReaderFuchsia.ChildThreads (2487 ms) ScopedTaskSuspend appears to try relatively hard to suspend, and without retrying indefinitely it's not clear how to do a better job. Retrying forever isn't suitable for production code though, where it would cause the crash reporter to hang. Bug: fuchsia:US-553 Change-Id: Ie233d2f5578cb8c35ce47207df4f1f8d2e1152f1 Reviewed-on: https://chromium-review.googlesource.com/c/1328022 Reviewed-by: Francois Rousseau <frousseau@google.com> Commit-Queue: Scott Graham <scottmg@chromium.org> --- snapshot/fuchsia/process_reader_fuchsia_test.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/snapshot/fuchsia/process_reader_fuchsia_test.cc b/snapshot/fuchsia/process_reader_fuchsia_test.cc index fe640082..df20bd33 100644 --- a/snapshot/fuchsia/process_reader_fuchsia_test.cc +++ b/snapshot/fuchsia/process_reader_fuchsia_test.cc @@ -166,7 +166,10 @@ class ThreadsChildTest : public MultiprocessExec { DISALLOW_COPY_AND_ASSIGN(ThreadsChildTest); }; -TEST(ProcessReaderFuchsia, ChildThreads) { +// TODO(scottmg): US-553. ScopedTaskSuspend fails sometimes, with a 50ms +// timeout. Currently unclear how to make that more reliable, so disable the +// test for now as otherwise it flakes. +TEST(ProcessReaderFuchsia, DISABLED_ChildThreads) { ThreadsChildTest test; test.Run(); } From 656fa55c74a8cb0fec9cfd0bf1c9135390c9831f Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 14 Nov 2018 10:15:50 -0800 Subject: [PATCH 080/401] Refactor ProcessReaderWin to use ProcessMemoryWin Remove ProcessReaderWin's ReadMemory() and ReadAvailableMemory() methods and replace their uses with a new method that exposes an instance of ProcessMemoryWin instead. BUG=crashpad:262 Change-Id: Ief5b660b0504d7a740ee53c7cd2fa7672ae56249 Reviewed-on: https://chromium-review.googlesource.com/c/1278830 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- snapshot/win/capture_memory_delegate_win.cc | 3 +- snapshot/win/exception_snapshot_win.cc | 10 ++-- snapshot/win/memory_snapshot_win.cc | 2 +- snapshot/win/module_snapshot_win.cc | 6 +- snapshot/win/pe_image_annotations_reader.cc | 14 ++--- snapshot/win/process_reader_win.cc | 65 +++------------------ snapshot/win/process_reader_win.h | 23 ++------ snapshot/win/process_reader_win_test.cc | 4 +- snapshot/win/process_snapshot_win.cc | 33 ++++++----- snapshot/win/process_subrange_reader.cc | 4 +- 10 files changed, 51 insertions(+), 113 deletions(-) diff --git a/snapshot/win/capture_memory_delegate_win.cc b/snapshot/win/capture_memory_delegate_win.cc index fc1c608b..b652f4a4 100644 --- a/snapshot/win/capture_memory_delegate_win.cc +++ b/snapshot/win/capture_memory_delegate_win.cc @@ -39,7 +39,8 @@ bool CaptureMemoryDelegateWin::Is64Bit() const { bool CaptureMemoryDelegateWin::ReadMemory(uint64_t at, uint64_t num_bytes, void* into) const { - return process_reader_->ReadMemory(at, num_bytes, into); + return process_reader_->Memory()->Read( + at, base::checked_cast<size_t>(num_bytes), into); } std::vector<CheckedRange<uint64_t>> CaptureMemoryDelegateWin::GetReadableRanges( diff --git a/snapshot/win/exception_snapshot_win.cc b/snapshot/win/exception_snapshot_win.cc index 64b53424..cba6f121 100644 --- a/snapshot/win/exception_snapshot_win.cc +++ b/snapshot/win/exception_snapshot_win.cc @@ -176,9 +176,9 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers( CPUContext* context, CPUContextUnion* context_union)) { ExceptionPointersType exception_pointers; - if (!process_reader->ReadMemory(exception_pointers_address, - sizeof(exception_pointers), - &exception_pointers)) { + if (!process_reader->Memory()->Read(exception_pointers_address, + sizeof(exception_pointers), + &exception_pointers)) { LOG(ERROR) << "EXCEPTION_POINTERS read failed"; return false; } @@ -188,7 +188,7 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers( } ExceptionRecordType first_record; - if (!process_reader->ReadMemory( + if (!process_reader->Memory()->Read( static_cast<WinVMAddress>(exception_pointers.ExceptionRecord), sizeof(first_record), &first_record)) { @@ -240,7 +240,7 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers( } ContextType context_record; - if (!process_reader->ReadMemory( + if (!process_reader->Memory()->Read( static_cast<WinVMAddress>(exception_pointers.ContextRecord), sizeof(context_record), &context_record)) { diff --git a/snapshot/win/memory_snapshot_win.cc b/snapshot/win/memory_snapshot_win.cc index 17e8ac11..d56b9520 100644 --- a/snapshot/win/memory_snapshot_win.cc +++ b/snapshot/win/memory_snapshot_win.cc @@ -60,7 +60,7 @@ bool MemorySnapshotWin::Read(Delegate* delegate) const { } std::unique_ptr<uint8_t[]> buffer(new uint8_t[size_]); - if (!process_reader_->ReadMemory(address_, size_, buffer.get())) { + if (!process_reader_->Memory()->Read(address_, size_, buffer.get())) { return false; } return delegate->MemorySnapshotDelegateRead(buffer.get(), size_); diff --git a/snapshot/win/module_snapshot_win.cc b/snapshot/win/module_snapshot_win.cc index 880e9da0..d76a187e 100644 --- a/snapshot/win/module_snapshot_win.cc +++ b/snapshot/win/module_snapshot_win.cc @@ -278,7 +278,7 @@ void ModuleSnapshotWin::GetCrashpadExtraMemoryRanges( std::vector<SimpleAddressRangeBag::Entry> simple_ranges( SimpleAddressRangeBag::num_entries); - if (!process_reader_->ReadMemory( + if (!process_reader_->Memory()->Read( crashpad_info.extra_address_ranges, simple_ranges.size() * sizeof(simple_ranges[0]), &simple_ranges[0])) { @@ -304,8 +304,8 @@ void ModuleSnapshotWin::GetCrashpadUserMinidumpStreams( for (uint64_t cur = crashpad_info.user_data_minidump_stream_head; cur;) { internal::UserDataMinidumpStreamListEntry list_entry; - if (!process_reader_->ReadMemory( - cur, sizeof(list_entry), &list_entry)) { + if (!process_reader_->Memory()->Read( + cur, sizeof(list_entry), &list_entry)) { LOG(WARNING) << "could not read user data stream entry from " << base::UTF16ToUTF8(name_); return; diff --git a/snapshot/win/pe_image_annotations_reader.cc b/snapshot/win/pe_image_annotations_reader.cc index 67961457..4c1f66fd 100644 --- a/snapshot/win/pe_image_annotations_reader.cc +++ b/snapshot/win/pe_image_annotations_reader.cc @@ -92,7 +92,7 @@ void PEImageAnnotationsReader::ReadCrashpadSimpleAnnotations( std::vector<SimpleStringDictionary::Entry> simple_annotations(SimpleStringDictionary::num_entries); - if (!process_reader_->ReadMemory( + if (!process_reader_->Memory()->Read( crashpad_info.simple_annotations, simple_annotations.size() * sizeof(simple_annotations[0]), &simple_annotations[0])) { @@ -127,9 +127,9 @@ void PEImageAnnotationsReader::ReadCrashpadAnnotationsList( } process_types::AnnotationList<Traits> annotation_list_object; - if (!process_reader_->ReadMemory(crashpad_info.annotations_list, - sizeof(annotation_list_object), - &annotation_list_object)) { + if (!process_reader_->Memory()->Read(crashpad_info.annotations_list, + sizeof(annotation_list_object), + &annotation_list_object)) { LOG(WARNING) << "could not read annotations list object in " << base::UTF16ToUTF8(name_); return; @@ -140,7 +140,7 @@ void PEImageAnnotationsReader::ReadCrashpadAnnotationsList( current.link_node != annotation_list_object.tail_pointer && index < kMaxNumberOfAnnotations; ++index) { - if (!process_reader_->ReadMemory( + if (!process_reader_->Memory()->Read( current.link_node, sizeof(current), ¤t)) { LOG(WARNING) << "could not read annotation at index " << index << " in " << base::UTF16ToUTF8(name_); @@ -155,7 +155,7 @@ void PEImageAnnotationsReader::ReadCrashpadAnnotationsList( snapshot.type = current.type; char name[Annotation::kNameMaxLength]; - if (!process_reader_->ReadMemory(current.name, arraysize(name), name)) { + if (!process_reader_->Memory()->Read(current.name, arraysize(name), name)) { LOG(WARNING) << "could not read annotation name at index " << index << " in " << base::UTF16ToUTF8(name_); continue; @@ -167,7 +167,7 @@ void PEImageAnnotationsReader::ReadCrashpadAnnotationsList( size_t value_length = std::min(static_cast<size_t>(current.size), Annotation::kValueMaxSize); snapshot.value.resize(value_length); - if (!process_reader_->ReadMemory( + if (!process_reader_->Memory()->Read( current.value, value_length, snapshot.value.data())) { LOG(WARNING) << "could not read annotation value at index " << index << " in " << base::UTF16ToUTF8(name_); diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index 2fa02584..16280e96 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -204,6 +204,7 @@ ProcessReaderWin::Thread::Thread() ProcessReaderWin::ProcessReaderWin() : process_(INVALID_HANDLE_VALUE), process_info_(), + process_memory_(), threads_(), modules_(), suspension_state_(), @@ -220,67 +221,15 @@ bool ProcessReaderWin::Initialize(HANDLE process, process_ = process; suspension_state_ = suspension_state; - process_info_.Initialize(process); + if (!process_info_.Initialize(process)) + return false; + if (!process_memory_.Initialize(process)) + return false; INITIALIZATION_STATE_SET_VALID(initialized_); return true; } -bool ProcessReaderWin::ReadMemory(WinVMAddress at, - WinVMSize num_bytes, - void* into) const { - if (num_bytes == 0) - return 0; - - SIZE_T bytes_read; - if (!ReadProcessMemory(process_, - reinterpret_cast<void*>(at), - into, - base::checked_cast<SIZE_T>(num_bytes), - &bytes_read) || - num_bytes != bytes_read) { - PLOG(ERROR) << "ReadMemory at 0x" << std::hex << at << std::dec << " of " - << num_bytes << " bytes failed"; - return false; - } - return true; -} - -WinVMSize ProcessReaderWin::ReadAvailableMemory(WinVMAddress at, - WinVMSize num_bytes, - void* into) const { - if (num_bytes == 0) - return 0; - - auto ranges = process_info_.GetReadableRanges( - CheckedRange<WinVMAddress, WinVMSize>(at, num_bytes)); - - // We only read up until the first unavailable byte, so we only read from the - // first range. If we have no ranges, then no bytes were accessible anywhere - // in the range. - if (ranges.empty()) { - LOG(ERROR) << base::StringPrintf( - "range at 0x%llx, size 0x%llx completely inaccessible", at, num_bytes); - return 0; - } - - // If the start address was adjusted, we couldn't read even the first - // requested byte. - if (ranges.front().base() != at) { - LOG(ERROR) << base::StringPrintf( - "start of range at 0x%llx, size 0x%llx inaccessible", at, num_bytes); - return 0; - } - - DCHECK_LE(ranges.front().size(), num_bytes); - - // If we fail on a normal read, then something went very wrong. - if (!ReadMemory(ranges.front().base(), ranges.front().size(), into)) - return 0; - - return ranges.front().size(); -} - bool ProcessReaderWin::StartTime(timeval* start_time) const { FILETIME creation, exit, kernel, user; if (!GetProcessTimes(process_, &creation, &exit, &kernel, &user)) { @@ -398,7 +347,7 @@ void ProcessReaderWin::ReadThreadData(bool is_64_reading_32) { process_types::NT_TIB<Traits> tib; thread.teb_address = thread_basic_info.TebBaseAddress; thread.teb_size = sizeof(process_types::TEB<Traits>); - if (ReadMemory(thread.teb_address, sizeof(tib), &tib)) { + if (process_memory_.Read(thread.teb_address, sizeof(tib), &tib)) { WinVMAddress base = 0; WinVMAddress limit = 0; // If we're reading a WOW64 process, then the TIB we just retrieved is the @@ -409,7 +358,7 @@ void ProcessReaderWin::ReadThreadData(bool is_64_reading_32) { thread.teb_address = tib.Wow64Teb; thread.teb_size = sizeof(process_types::TEB<process_types::internal::Traits32>); - if (ReadMemory(thread.teb_address, sizeof(tib32), &tib32)) { + if (process_memory_.Read(thread.teb_address, sizeof(tib32), &tib32)) { base = tib32.StackBase; limit = tib32.StackLimit; } diff --git a/snapshot/win/process_reader_win.h b/snapshot/win/process_reader_win.h index 1794a51a..a4e32aaf 100644 --- a/snapshot/win/process_reader_win.h +++ b/snapshot/win/process_reader_win.h @@ -23,6 +23,7 @@ #include "base/macros.h" #include "build/build_config.h" #include "util/misc/initialization_state_dcheck.h" +#include "util/process/process_memory_win.h" #include "util/win/address_types.h" #include "util/win/process_info.h" @@ -84,25 +85,8 @@ class ProcessReaderWin { //! \return `true` if the target task is a 64-bit process. bool Is64Bit() const { return process_info_.Is64Bit(); } - //! \brief Attempts to read \a num_bytes bytes from the target process - //! starting at address \a at into \a into. - //! - //! \return `true` if the entire region could be read, or `false` with an - //! error logged. - //! - //! \sa ReadAvailableMemory - bool ReadMemory(WinVMAddress at, WinVMSize num_bytes, void* into) const; - - //! \brief Attempts to read \a num_bytes bytes from the target process - //! starting at address \a at into \a into. If some of the specified range - //! is not accessible, reads up to the first inaccessible byte. - //! - //! \return The actual number of bytes read. - //! - //! \sa ReadMemory - WinVMSize ReadAvailableMemory(WinVMAddress at, - WinVMSize num_bytes, - void* into) const; + //! \brief Return a memory reader for the target process. + const ProcessMemoryWin* Memory() const { return &process_memory_; } //! \brief Determines the target process' start time. //! @@ -145,6 +129,7 @@ class ProcessReaderWin { HANDLE process_; ProcessInfo process_info_; + ProcessMemoryWin process_memory_; std::vector<Thread> threads_; std::vector<ProcessInfo::Module> modules_; ProcessSuspensionState suspension_state_; diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index d0d4d96f..0f122fbd 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -43,7 +43,7 @@ TEST(ProcessReaderWin, SelfBasic) { static constexpr char kTestMemory[] = "Some test memory"; char buffer[arraysize(kTestMemory)]; - ASSERT_TRUE(process_reader.ReadMemory( + ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast<uintptr_t>(kTestMemory), sizeof(kTestMemory), &buffer)); EXPECT_STREQ(kTestMemory, buffer); } @@ -72,7 +72,7 @@ class ProcessReaderChild final : public WinMultiprocess { char buffer[sizeof(kTestMemory)]; ASSERT_TRUE( - process_reader.ReadMemory(address, sizeof(kTestMemory), &buffer)); + process_reader.Memory()->Read(address, sizeof(kTestMemory), &buffer)); EXPECT_EQ(strcmp(kTestMemory, buffer), 0); } diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index 289f50c0..7f1f93a0 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -21,7 +21,7 @@ #include <utility> #include "base/logging.h" -#include "base/strings/stringprintf.h" +#include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" #include "util/misc/from_pointer_cast.h" #include "util/misc/time.h" @@ -63,9 +63,9 @@ bool ProcessSnapshotWin::Initialize( if (exception_information_address != 0) { ExceptionInformation exception_information = {}; - if (!process_reader_.ReadMemory(exception_information_address, - sizeof(exception_information), - &exception_information)) { + if (!process_reader_.Memory()->Read(exception_information_address, + sizeof(exception_information), + &exception_information)) { LOG(WARNING) << "ReadMemory ExceptionInformation failed"; return false; } @@ -298,9 +298,9 @@ void ProcessSnapshotWin::InitializeUnloadedModules() { FromPointerCast<WinVMAddress>(event_trace_address); Traits::Pointer pointer_to_array; - if (!process_reader_.ReadMemory(address_in_target_process, - sizeof(pointer_to_array), - &pointer_to_array)) { + if (!process_reader_.Memory()->Read(address_in_target_process, + sizeof(pointer_to_array), + &pointer_to_array)) { LOG(ERROR) << "failed to read target address"; return; } @@ -311,7 +311,7 @@ void ProcessSnapshotWin::InitializeUnloadedModules() { const size_t data_size = *element_size * *element_count; std::vector<uint8_t> data(data_size); - if (!process_reader_.ReadMemory(pointer_to_array, data_size, &data[0])) { + if (!process_reader_.Memory()->Read(pointer_to_array, data_size, &data[0])) { LOG(ERROR) << "failed to read unloaded module data"; return; } @@ -377,14 +377,15 @@ void ProcessSnapshotWin::InitializePebData( AddMemorySnapshot(peb_address, peb_size, &extra_memory_); process_types::PEB<Traits> peb_data; - if (!process_reader_.ReadMemory(peb_address, peb_size, &peb_data)) { + if (!process_reader_.Memory()->Read( + peb_address, base::checked_cast<size_t>(peb_size), &peb_data)) { LOG(ERROR) << "ReadMemory PEB"; return; } process_types::PEB_LDR_DATA<Traits> peb_ldr_data; AddMemorySnapshot(peb_data.Ldr, sizeof(peb_ldr_data), &extra_memory_); - if (!process_reader_.ReadMemory( + if (!process_reader_.Memory()->Read( peb_data.Ldr, sizeof(peb_ldr_data), &peb_ldr_data)) { LOG(ERROR) << "ReadMemory PEB_LDR_DATA"; } else { @@ -406,9 +407,9 @@ void ProcessSnapshotWin::InitializePebData( } process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters; - if (!process_reader_.ReadMemory(peb_data.ProcessParameters, - sizeof(process_parameters), - &process_parameters)) { + if (!process_reader_.Memory()->Read(peb_data.ProcessParameters, + sizeof(process_parameters), + &process_parameters)) { LOG(ERROR) << "ReadMemory RTL_USER_PROCESS_PARAMETERS"; return; } @@ -496,7 +497,7 @@ void ProcessSnapshotWin::AddMemorySnapshotForLdrLIST_ENTRY( for (;;) { // |cur| is the pointer to LIST_ENTRY embedded in the LDR_DATA_TABLE_ENTRY. // So we need to offset back to the beginning of the structure. - if (!process_reader_.ReadMemory( + if (!process_reader_.Memory()->Read( cur - offset_of_member, sizeof(entry), &entry)) { return; } @@ -520,7 +521,7 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock( // be more than enough. std::wstring env_block; env_block.resize(32768); - WinVMSize bytes_read = process_reader_.ReadAvailableMemory( + size_t bytes_read = process_reader_.Memory()->ReadAvailableMemory( start_of_environment_block, env_block.size() * sizeof(env_block[0]), &env_block[0]); @@ -543,7 +544,7 @@ void ProcessSnapshotWin::ReadLock( // RTL_CRITICAL_SECTION_DEBUG. process_types::RTL_CRITICAL_SECTION<Traits> critical_section; - if (!process_reader_.ReadMemory( + if (!process_reader_.Memory()->Read( start, sizeof(critical_section), &critical_section)) { LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION"; return; diff --git a/snapshot/win/process_subrange_reader.cc b/snapshot/win/process_subrange_reader.cc index 996fbdf3..124c5d02 100644 --- a/snapshot/win/process_subrange_reader.cc +++ b/snapshot/win/process_subrange_reader.cc @@ -15,6 +15,7 @@ #include "snapshot/win/process_subrange_reader.h" #include "base/logging.h" +#include "base/numerics/safe_conversions.h" #include "snapshot/win/process_reader_win.h" namespace crashpad { @@ -82,7 +83,8 @@ bool ProcessSubrangeReader::ReadMemory(WinVMAddress address, return false; } - return process_reader_->ReadMemory(address, size, into); + return process_reader_->Memory()->Read( + address, base::checked_cast<size_t>(size), into); } bool ProcessSubrangeReader::InitializeInternal(ProcessReaderWin* process_reader, From 1c4c1277e87071d8752747a1e40875a11da1a7f5 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 14 Nov 2018 10:20:20 -0800 Subject: [PATCH 081/401] Add a ProcessSnapshot::Memory method Add a method to the ProcessSnapshot to expose a ProcessMemory object to allow reading memory directly from the underlying process. CQ-DEPEND=CL:1278830 BUG=crashpad:262 Change-Id: Ied2a5510a9b051c7ac8c41cdd060e8daa531086e Reviewed-on: https://chromium-review.googlesource.com/c/1315428 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/fuchsia/process_reader_fuchsia.h | 2 +- snapshot/fuchsia/process_snapshot_fuchsia.cc | 5 +++++ snapshot/fuchsia/process_snapshot_fuchsia.h | 1 + snapshot/linux/process_reader_linux.h | 2 +- snapshot/linux/process_snapshot_linux.cc | 5 +++++ snapshot/linux/process_snapshot_linux.h | 1 + snapshot/mac/process_snapshot_mac.cc | 6 ++++++ snapshot/mac/process_snapshot_mac.h | 1 + snapshot/minidump/process_snapshot_minidump.cc | 5 +++++ snapshot/minidump/process_snapshot_minidump.h | 1 + snapshot/process_snapshot.h | 9 +++++++++ snapshot/sanitized/process_snapshot_sanitized.cc | 6 ++++++ snapshot/sanitized/process_snapshot_sanitized.h | 1 + snapshot/test/test_process_snapshot.cc | 7 ++++++- snapshot/test/test_process_snapshot.h | 12 ++++++++++++ snapshot/win/process_snapshot_win.cc | 5 +++++ snapshot/win/process_snapshot_win.h | 1 + 17 files changed, 67 insertions(+), 3 deletions(-) diff --git a/snapshot/fuchsia/process_reader_fuchsia.h b/snapshot/fuchsia/process_reader_fuchsia.h index 28a1e93e..36201af7 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.h +++ b/snapshot/fuchsia/process_reader_fuchsia.h @@ -109,7 +109,7 @@ class ProcessReaderFuchsia { const std::vector<Thread>& Threads(); //! \brief Return a memory reader for the target process. - ProcessMemory* Memory() { return process_memory_.get(); } + const ProcessMemory* Memory() const { return process_memory_.get(); } private: //! Performs lazy initialization of the \a modules_ vector on behalf of diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.cc b/snapshot/fuchsia/process_snapshot_fuchsia.cc index 6750c3d5..12122f61 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia.cc @@ -188,6 +188,11 @@ std::vector<const MemorySnapshot*> ProcessSnapshotFuchsia::ExtraMemory() const { return std::vector<const MemorySnapshot*>(); } +const ProcessMemory* ProcessSnapshotFuchsia::Memory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return process_reader_.Memory(); +} + void ProcessSnapshotFuchsia::InitializeThreads() { const std::vector<ProcessReaderFuchsia::Thread>& process_reader_threads = process_reader_.Threads(); diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.h b/snapshot/fuchsia/process_snapshot_fuchsia.h index 237e17df..15c3bb7a 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.h +++ b/snapshot/fuchsia/process_snapshot_fuchsia.h @@ -121,6 +121,7 @@ class ProcessSnapshotFuchsia : public ProcessSnapshot { std::vector<const MemoryMapRegionSnapshot*> MemoryMap() const override; std::vector<HandleSnapshot> Handles() const override; std::vector<const MemorySnapshot*> ExtraMemory() const override; + const ProcessMemory* Memory() const override; private: // Initializes threads_ on behalf of Initialize(). diff --git a/snapshot/linux/process_reader_linux.h b/snapshot/linux/process_reader_linux.h index dbe436a6..1b30f53e 100644 --- a/snapshot/linux/process_reader_linux.h +++ b/snapshot/linux/process_reader_linux.h @@ -120,7 +120,7 @@ class ProcessReaderLinux { pid_t ParentProcessID() const { return process_info_.ParentProcessID(); } //! \brief Return a memory reader for the target process. - ProcessMemory* Memory() { return connection_->Memory(); } + const ProcessMemory* Memory() const { return connection_->Memory(); } //! \brief Return a memory map of the target process. MemoryMap* GetMemoryMap() { return &memory_map_; } diff --git a/snapshot/linux/process_snapshot_linux.cc b/snapshot/linux/process_snapshot_linux.cc index 190e8691..041653a3 100644 --- a/snapshot/linux/process_snapshot_linux.cc +++ b/snapshot/linux/process_snapshot_linux.cc @@ -234,6 +234,11 @@ std::vector<const MemorySnapshot*> ProcessSnapshotLinux::ExtraMemory() const { return std::vector<const MemorySnapshot*>(); } +const ProcessMemory* ProcessSnapshotLinux::Memory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return process_reader_.Memory(); +} + void ProcessSnapshotLinux::InitializeThreads() { const std::vector<ProcessReaderLinux::Thread>& process_reader_threads = process_reader_.Threads(); diff --git a/snapshot/linux/process_snapshot_linux.h b/snapshot/linux/process_snapshot_linux.h index 49d648f9..236926d6 100644 --- a/snapshot/linux/process_snapshot_linux.h +++ b/snapshot/linux/process_snapshot_linux.h @@ -115,6 +115,7 @@ class ProcessSnapshotLinux final : public ProcessSnapshot { std::vector<const MemoryMapRegionSnapshot*> MemoryMap() const override; std::vector<HandleSnapshot> Handles() const override; std::vector<const MemorySnapshot*> ExtraMemory() const override; + const ProcessMemory* Memory() const override; private: void InitializeThreads(); diff --git a/snapshot/mac/process_snapshot_mac.cc b/snapshot/mac/process_snapshot_mac.cc index cf5233a9..68837ff4 100644 --- a/snapshot/mac/process_snapshot_mac.cc +++ b/snapshot/mac/process_snapshot_mac.cc @@ -217,6 +217,12 @@ std::vector<const MemorySnapshot*> ProcessSnapshotMac::ExtraMemory() const { return std::vector<const MemorySnapshot*>(); } +const ProcessMemory* ProcessSnapshotMac::Memory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/263 + return nullptr; +} + void ProcessSnapshotMac::InitializeThreads() { const std::vector<ProcessReaderMac::Thread>& process_reader_threads = process_reader_.Threads(); diff --git a/snapshot/mac/process_snapshot_mac.h b/snapshot/mac/process_snapshot_mac.h index 06bac749..2edc2220 100644 --- a/snapshot/mac/process_snapshot_mac.h +++ b/snapshot/mac/process_snapshot_mac.h @@ -131,6 +131,7 @@ class ProcessSnapshotMac final : public ProcessSnapshot { std::vector<const MemoryMapRegionSnapshot*> MemoryMap() const override; std::vector<HandleSnapshot> Handles() const override; std::vector<const MemorySnapshot*> ExtraMemory() const override; + const ProcessMemory* Memory() const override; private: // Initializes threads_ on behalf of Initialize(). diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 12738434..5cc5ad89 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -229,6 +229,11 @@ std::vector<const MemorySnapshot*> ProcessSnapshotMinidump::ExtraMemory() return std::vector<const MemorySnapshot*>(); } +const ProcessMemory* ProcessSnapshotMinidump::Memory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return nullptr; +} + bool ProcessSnapshotMinidump::InitializeCrashpadInfo() { const auto& stream_it = stream_map_.find(kMinidumpStreamTypeCrashpadInfo); if (stream_it == stream_map_.end()) { diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 3f256184..2a868a12 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -81,6 +81,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector<const MemoryMapRegionSnapshot*> MemoryMap() const override; std::vector<HandleSnapshot> Handles() const override; std::vector<const MemorySnapshot*> ExtraMemory() const override; + const ProcessMemory* Memory() const override; private: // Initializes data carried in a MinidumpCrashpadInfo stream on behalf of diff --git a/snapshot/process_snapshot.h b/snapshot/process_snapshot.h index 8d5520cd..f5859d22 100644 --- a/snapshot/process_snapshot.h +++ b/snapshot/process_snapshot.h @@ -31,6 +31,7 @@ class ExceptionSnapshot; class MemoryMapRegionSnapshot; class MemorySnapshot; class ModuleSnapshot; +class ProcessMemory; class SystemSnapshot; class ThreadSnapshot; class UnloadedModuleSnapshot; @@ -193,6 +194,14 @@ class ProcessSnapshot { //! are scoped to the lifetime of the ProcessSnapshot object that they //! were obtained from. virtual std::vector<const MemorySnapshot*> ExtraMemory() const = 0; + + //! \brief Returns a ProcessMemory object that allows accessing the process' + //! memory directly. + //! + //! \return A ProcessMemory object. The caller does not take ownership of this + //! object, it is scoped to the lifetime of the ProcessSnapshot object + //! that it was obtained from. + virtual const ProcessMemory* Memory() const = 0; }; } // namespace crashpad diff --git a/snapshot/sanitized/process_snapshot_sanitized.cc b/snapshot/sanitized/process_snapshot_sanitized.cc index 76caeb5a..20807b96 100644 --- a/snapshot/sanitized/process_snapshot_sanitized.cc +++ b/snapshot/sanitized/process_snapshot_sanitized.cc @@ -262,4 +262,10 @@ std::vector<const MemorySnapshot*> ProcessSnapshotSanitized::ExtraMemory() return snapshot_->ExtraMemory(); } +const ProcessMemory* ProcessSnapshotSanitized::Memory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://crashpad.chromium.org/bug/263 + return nullptr; +} + } // namespace crashpad diff --git a/snapshot/sanitized/process_snapshot_sanitized.h b/snapshot/sanitized/process_snapshot_sanitized.h index f5cf5fa6..b5f0c406 100644 --- a/snapshot/sanitized/process_snapshot_sanitized.h +++ b/snapshot/sanitized/process_snapshot_sanitized.h @@ -83,6 +83,7 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot { std::vector<const MemoryMapRegionSnapshot*> MemoryMap() const override; std::vector<HandleSnapshot> Handles() const override; std::vector<const MemorySnapshot*> ExtraMemory() const override; + const ProcessMemory* Memory() const override; private: // Only used when annotations_whitelist_ != nullptr. diff --git a/snapshot/test/test_process_snapshot.cc b/snapshot/test/test_process_snapshot.cc index c430fd99..1a313705 100644 --- a/snapshot/test/test_process_snapshot.cc +++ b/snapshot/test/test_process_snapshot.cc @@ -35,7 +35,8 @@ TestProcessSnapshot::TestProcessSnapshot() exception_(), memory_map_(), handles_(), - extra_memory_() { + extra_memory_(), + process_memory_() { } TestProcessSnapshot::~TestProcessSnapshot() { @@ -126,5 +127,9 @@ std::vector<const MemorySnapshot*> TestProcessSnapshot::ExtraMemory() const { return extra_memory; } +const ProcessMemory* TestProcessSnapshot::Memory() const { + return process_memory_.get(); +} + } // namespace test } // namespace crashpad diff --git a/snapshot/test/test_process_snapshot.h b/snapshot/test/test_process_snapshot.h index 5c63e121..bfa26abd 100644 --- a/snapshot/test/test_process_snapshot.h +++ b/snapshot/test/test_process_snapshot.h @@ -35,6 +35,7 @@ #include "snapshot/thread_snapshot.h" #include "snapshot/unloaded_module_snapshot.h" #include "util/misc/uuid.h" +#include "util/process/process_memory.h" namespace crashpad { namespace test { @@ -134,6 +135,15 @@ class TestProcessSnapshot final : public ProcessSnapshot { extra_memory_.push_back(std::move(extra_memory)); } + //! \brief Add a process memory object to be returned by Memory(). + //! + //! \param[in] process_memory The memory object that will be returned by + //! Memory(). The TestProcessSnapshot object takes ownership of \a + //! extra_memory. + void SetProcessMemory(std::unique_ptr<ProcessMemory> process_memory) { + process_memory_ = std::move(process_memory); + } + // ProcessSnapshot: pid_t ProcessID() const override; @@ -153,6 +163,7 @@ class TestProcessSnapshot final : public ProcessSnapshot { std::vector<const MemoryMapRegionSnapshot*> MemoryMap() const override; std::vector<HandleSnapshot> Handles() const override; std::vector<const MemorySnapshot*> ExtraMemory() const override; + const ProcessMemory* Memory() const override; private: pid_t process_id_; @@ -172,6 +183,7 @@ class TestProcessSnapshot final : public ProcessSnapshot { std::vector<std::unique_ptr<MemoryMapRegionSnapshot>> memory_map_; std::vector<HandleSnapshot> handles_; std::vector<std::unique_ptr<MemorySnapshot>> extra_memory_; + std::unique_ptr<ProcessMemory> process_memory_; DISALLOW_COPY_AND_ASSIGN(TestProcessSnapshot); }; diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index 7f1f93a0..af6fe4d2 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -232,6 +232,11 @@ std::vector<const MemorySnapshot*> ProcessSnapshotWin::ExtraMemory() const { return extra_memory; } +const ProcessMemory* ProcessSnapshotWin::Memory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return process_reader_.Memory(); +} + void ProcessSnapshotWin::InitializeThreads( bool gather_indirectly_referenced_memory, uint32_t indirectly_referenced_memory_cap) { diff --git a/snapshot/win/process_snapshot_win.h b/snapshot/win/process_snapshot_win.h index 9250c13c..092aaf16 100644 --- a/snapshot/win/process_snapshot_win.h +++ b/snapshot/win/process_snapshot_win.h @@ -129,6 +129,7 @@ class ProcessSnapshotWin final : public ProcessSnapshot { std::vector<const MemoryMapRegionSnapshot*> MemoryMap() const override; std::vector<HandleSnapshot> Handles() const override; std::vector<const MemorySnapshot*> ExtraMemory() const override; + const ProcessMemory* Memory() const override; private: // Initializes threads_ on behalf of Initialize(). From ad788280e4df2fee44b24694a74efb0ea38d869e Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 16 Nov 2018 13:00:48 -0800 Subject: [PATCH 082/401] fuchsia: Disable HTTPS tests to avoid (unavailable) dependency on BoringSSL Bug: crashpad:266 Bug: fuchsia:DX-690 Change-Id: Ica6c2d6d345cbda17fd67de69e7c770389808f63 Reviewed-on: https://chromium-review.googlesource.com/c/1340743 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- util/net/tls.gni | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6cfae819..c365099e 100644 --- a/DEPS +++ b/DEPS @@ -30,7 +30,7 @@ deps = { '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'd2c271a0671f81db24bce69631ba99d0c26f3a5b', + '4a6189577978b86fbd6935aec0d16a127803467c', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/util/net/tls.gni b/util/net/tls.gni index ed9aa861..f979b620 100644 --- a/util/net/tls.gni +++ b/util/net/tls.gni @@ -15,5 +15,8 @@ import("../../build/crashpad_buildconfig.gni") declare_args() { - crashpad_use_boringssl_for_http_transport_socket = crashpad_is_fuchsia + # TODO(scottmg): https://crbug.com/crashpad/266 fuchsia:DX-690: BoringSSL + # was removed from the Fuchsia SDK. Re-enable it when we have a way to acquire + # a BoringSSL lib again. + crashpad_use_boringssl_for_http_transport_socket = crashpad_is_in_fuchsia } From f42a579b8c847fa8560db0c6ed77a30e997d6860 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Fri, 16 Nov 2018 20:41:17 -0800 Subject: [PATCH 083/401] Add ProcessSnapshotMinidump::CustomMinidumpStreams() Add a method to ProcessSnapshotMinidump to expose a similar interface to ModuleSnapshot::CustomMinidumpStreams(). It's implemented on the process snapshot here because there is no way to map custom minidump streams back to a specific module. This allows implementing tests that inspect custom user streams in minidumps. Bug: 896019 Change-Id: I1673c342753e13d64bddcc0083ca29fa356deac7 Reviewed-on: https://chromium-review.googlesource.com/c/1271405 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- minidump/minidump_extensions.h | 8 +++ snapshot/BUILD.gn | 5 +- snapshot/minidump/minidump_stream.h | 42 +++++++++++++ .../minidump/process_snapshot_minidump.cc | 49 ++++++++++++++- snapshot/minidump/process_snapshot_minidump.h | 15 +++++ .../process_snapshot_minidump_test.cc | 62 +++++++++++++++++++ snapshot/snapshot.gyp | 1 + 7 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 snapshot/minidump/minidump_stream.h diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h index f3701dc2..bdaaa483 100644 --- a/minidump/minidump_extensions.h +++ b/minidump/minidump_extensions.h @@ -92,10 +92,18 @@ enum MinidumpStreamType : uint32_t { //! \sa MemoryInfoListStream kMinidumpStreamTypeMemoryInfoList = MemoryInfoListStream, + //! \brief The last reserved minidump stream. + //! + //! \sa MemoryInfoListStream + kMinidumpStreamTypeLastReservedStream = LastReservedStream, + // 0x4350 = "CP" //! \brief The stream type for MinidumpCrashpadInfo. kMinidumpStreamTypeCrashpadInfo = 0x43500001, + + //! \brief The last reserved crashpad stream. + kMinidumpStreamTypeCrashpadLastReservedStream = 0x4350ffff, }; //! \brief A variable-length UTF-8-encoded string carried within a minidump diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 3e75817d..cbc853ad 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -36,16 +36,17 @@ static_library("snapshot") { "memory_snapshot.cc", "memory_snapshot.h", "memory_snapshot_generic.h", + "minidump/memory_snapshot_minidump.cc", + "minidump/memory_snapshot_minidump.h", "minidump/minidump_annotation_reader.cc", "minidump/minidump_annotation_reader.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/memory_snapshot_minidump.cc", - "minidump/memory_snapshot_minidump.h", "minidump/module_snapshot_minidump.cc", "minidump/module_snapshot_minidump.h", "minidump/process_snapshot_minidump.cc", diff --git a/snapshot/minidump/minidump_stream.h b/snapshot/minidump/minidump_stream.h new file mode 100644 index 00000000..1c75cb63 --- /dev/null +++ b/snapshot/minidump/minidump_stream.h @@ -0,0 +1,42 @@ +// Copyright 2018 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_MINIDUMP_MINIDUMP_STREAM_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_STREAM_H_ + +#include <stdint.h> + +#include <vector> + +namespace crashpad { + +//! \brief Stores a minidump stream along with its stream ID. +class MinidumpStream { + public: + MinidumpStream(uint32_t stream_type, std::vector<uint8_t> data) + : stream_type_(stream_type), data_(data){}; + + uint32_t stream_type() const { return stream_type_; } + const std::vector<uint8_t>& data() const { return data_; } + + private: + uint32_t stream_type_; + std::vector<uint8_t> data_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpStream); +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_STREAM_H_ diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 5cc5ad89..620f5de9 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -16,6 +16,7 @@ #include <utility> +#include "minidump/minidump_extensions.h" #include "snapshot/memory_map_region_snapshot.h" #include "snapshot/minidump/minidump_simple_string_dictionary_reader.h" #include "util/file/file_io.h" @@ -45,7 +46,11 @@ ProcessSnapshotMinidump::ProcessSnapshotMinidump() stream_directory_(), stream_map_(), modules_(), + threads_(), unloaded_modules_(), + mem_regions_(), + mem_regions_exposed_(), + custom_streams_(), crashpad_info_(), system_snapshot_(), arch_(CPUArchitecture::kCPUArchitectureUnknown), @@ -109,7 +114,8 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { !InitializeModules() || !InitializeSystemSnapshot() || !InitializeMemoryInfo() || - !InitializeThreads()) { + !InitializeThreads() || + !InitializeCustomMinidumpStreams()) { return false; } @@ -234,6 +240,18 @@ const ProcessMemory* ProcessSnapshotMinidump::Memory() const { return nullptr; } +std::vector<const MinidumpStream*> +ProcessSnapshotMinidump::CustomMinidumpStreams() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + std::vector<const MinidumpStream*> result; + result.reserve(custom_streams_.size()); + for (const auto& custom_stream : custom_streams_) { + result.push_back(custom_stream.get()); + } + return result; +} + bool ProcessSnapshotMinidump::InitializeCrashpadInfo() { const auto& stream_it = stream_map_.find(kMinidumpStreamTypeCrashpadInfo); if (stream_it == stream_map_.end()) { @@ -529,4 +547,33 @@ bool ProcessSnapshotMinidump::InitializeSystemSnapshot() { return true; } +bool ProcessSnapshotMinidump::InitializeCustomMinidumpStreams() { + for (size_t i = 0; i < stream_directory_.size(); i++) { + const auto& stream = stream_directory_[i]; + + // Filter out reserved minidump and crashpad streams. + const uint32_t stream_type = stream.StreamType; + if (stream_type <= + MinidumpStreamType::kMinidumpStreamTypeLastReservedStream || + (stream_type >= MinidumpStreamType::kMinidumpStreamTypeCrashpadInfo && + stream_type <= MinidumpStreamType:: + kMinidumpStreamTypeCrashpadLastReservedStream)) { + continue; + } + + std::vector<uint8_t> data(stream.Location.DataSize); + if (!file_reader_->SeekSet(stream.Location.Rva) || + !file_reader_->ReadExactly(data.data(), data.size())) { + LOG(ERROR) << "Failed to read stream with ID 0x" << std::hex + << stream_type << std::dec << " at index " << i; + return false; + } + + custom_streams_.push_back( + std::make_unique<MinidumpStream>(stream_type, std::move(data))); + } + + return true; +} + } // namespace crashpad diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 2a868a12..8653d33a 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -29,6 +29,7 @@ #include "minidump/minidump_extensions.h" #include "snapshot/exception_snapshot.h" #include "snapshot/memory_snapshot.h" +#include "snapshot/minidump/minidump_stream.h" #include "snapshot/minidump/module_snapshot_minidump.h" #include "snapshot/minidump/system_snapshot_minidump.h" #include "snapshot/minidump/thread_snapshot_minidump.h" @@ -83,6 +84,16 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector<const MemorySnapshot*> ExtraMemory() const override; const ProcessMemory* Memory() const override; + //! \brief Returns a list of custom minidump streams. This routine is the + //! equivalent of ModuleSnapshot::CustomMinidumpStreams(), except that in + //! a minidump it is impossible to associate a custom stream to a specific + //! module. + //! + //! \return The caller does not take ownership of the returned objects, they + //! are scoped to the lifetime of the ProcessSnapshotMinidump object that + //! they were obtained from. + std::vector<const MinidumpStream*> CustomMinidumpStreams() const; + private: // Initializes data carried in a MinidumpCrashpadInfo stream on behalf of // Initialize(). @@ -115,6 +126,9 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { // Initialize(). bool InitializeMiscInfo(); + // Initializes custom minidump streams. + bool InitializeCustomMinidumpStreams(); + MINIDUMP_HEADER header_; std::vector<MINIDUMP_DIRECTORY> stream_directory_; std::map<MinidumpStreamType, const MINIDUMP_LOCATION_DESCRIPTOR*> stream_map_; @@ -124,6 +138,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector<std::unique_ptr<internal::MemoryMapRegionSnapshotMinidump>> mem_regions_; std::vector<const MemoryMapRegionSnapshot*> mem_regions_exposed_; + std::vector<std::unique_ptr<MinidumpStream>> custom_streams_; MinidumpCrashpadInfo crashpad_info_; internal::SystemSnapshotMinidump system_snapshot_; CPUArchitecture arch_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 4d744545..52b09920 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -1109,6 +1109,68 @@ TEST(ProcessSnapshotMinidump, Stacks) { EXPECT_EQ(delegate.result, minidump_stack); } +TEST(ProcessSnapshotMinidump, CustomMinidumpStreams) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + ASSERT_TRUE(string_file.Write(&header, sizeof(header))); + + static const char kStreamReservedData[] = "A string"; + static const char kStreamUnreservedData[] = "Another string"; + // In the minidump reserved range + constexpr MinidumpStreamType kStreamTypeReserved1 = + (MinidumpStreamType)0x1111; + // In the crashpad reserved range + constexpr MinidumpStreamType kStreamTypeReserved2 = + (MinidumpStreamType)0x43501111; + constexpr MinidumpStreamType kStreamTypeUnreserved = + (MinidumpStreamType)0xffffffff; + + MINIDUMP_DIRECTORY misc_directory = {}; + RVA reserved1_offset = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE( + string_file.Write(kStreamReservedData, sizeof(kStreamReservedData))); + RVA reserved2_offset = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE( + string_file.Write(kStreamReservedData, sizeof(kStreamReservedData))); + RVA unreserved_offset = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE( + string_file.Write(kStreamUnreservedData, sizeof(kStreamUnreservedData))); + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + misc_directory.StreamType = kStreamTypeReserved1; + misc_directory.Location.DataSize = sizeof(kStreamReservedData); + misc_directory.Location.Rva = reserved1_offset; + ASSERT_TRUE(string_file.Write(&misc_directory, sizeof(misc_directory))); + + misc_directory.StreamType = kStreamTypeReserved2; + misc_directory.Location.DataSize = sizeof(kStreamReservedData); + misc_directory.Location.Rva = reserved2_offset; + ASSERT_TRUE(string_file.Write(&misc_directory, sizeof(misc_directory))); + + misc_directory.StreamType = kStreamTypeUnreserved; + misc_directory.Location.DataSize = sizeof(kStreamUnreservedData); + misc_directory.Location.Rva = unreserved_offset; + ASSERT_TRUE(string_file.Write(&misc_directory, sizeof(misc_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 3; + ASSERT_TRUE(string_file.SeekSet(0)); + ASSERT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + ASSERT_TRUE(process_snapshot.Initialize(&string_file)); + + auto custom_streams = process_snapshot.CustomMinidumpStreams(); + ASSERT_EQ(custom_streams.size(), 1U); + EXPECT_EQ(custom_streams[0]->stream_type(), (uint32_t)kStreamTypeUnreserved); + + auto stream_data = custom_streams[0]->data(); + EXPECT_EQ(stream_data.size(), sizeof(kStreamUnreservedData)); + EXPECT_STREQ((char*)&stream_data.front(), kStreamUnreservedData); +} + } // namespace } // namespace test } // namespace crashpad diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index dd60b0c1..ac7de298 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -111,6 +111,7 @@ 'minidump/minidump_annotation_reader.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', From 083fd52cc3c1161c9fd0324e87ce4171612cfafa Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Fri, 16 Nov 2018 22:38:53 -0800 Subject: [PATCH 084/401] linux: Fix build failure on ARM/MIPS Add const to ProcessMemory pointers from ProcessReaderLinux::Memory(). This code is ifdef'd to only build on ARM/MIPS. Change-Id: I93983a83d06bd5bd338b93babdb326fa94925c53 Reviewed-on: https://chromium-review.googlesource.com/c/1341228 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- snapshot/linux/exception_snapshot_linux.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/snapshot/linux/exception_snapshot_linux.cc b/snapshot/linux/exception_snapshot_linux.cc index 4256f942..cd40b3b1 100644 --- a/snapshot/linux/exception_snapshot_linux.cc +++ b/snapshot/linux/exception_snapshot_linux.cc @@ -126,7 +126,7 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>( context_.arm = &context_union_.arm; CPUContextARM* dest_context = context_.arm; - ProcessMemory* memory = reader->Memory(); + const ProcessMemory* memory = reader->Memory(); LinuxVMAddress gprs_address = context_address + offsetof(UContext<ContextTraits32>, mcontext32) + @@ -203,7 +203,7 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>( context_.arm64 = &context_union_.arm64; CPUContextARM64* dest_context = context_.arm64; - ProcessMemory* memory = reader->Memory(); + const ProcessMemory* memory = reader->Memory(); LinuxVMAddress gprs_address = context_address + offsetof(UContext<ContextTraits64>, mcontext64) + @@ -274,7 +274,7 @@ template <typename Traits> static bool ReadContext(ProcessReaderLinux* reader, LinuxVMAddress context_address, typename Traits::CPUContext* dest_context) { - ProcessMemory* memory = reader->Memory(); + const ProcessMemory* memory = reader->Memory(); LinuxVMAddress gregs_address = context_address + offsetof(UContext<Traits>, mcontext) + From 3ca07134305c0bdaee8e4db96e550e8a66d1aaca Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Mon, 26 Nov 2018 15:13:08 -0800 Subject: [PATCH 085/401] roll googletest to b18d39 * 71d4fc is the change fixing death tests on Fuchsia where the exception was still caught by the system exception handler * we need up to b18d39 to make Windows happy Change-Id: Ic938caabe3dde93ebda520b389b166d78c4460a6 Reviewed-on: https://chromium-review.googlesource.com/c/1350931 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- DEPS | 2 +- third_party/gtest/BUILD.gn | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/DEPS b/DEPS index c365099e..635e1416 100644 --- a/DEPS +++ b/DEPS @@ -24,7 +24,7 @@ deps = { '6fe4a3251488f7af86d64fc25cf442e817cf6133', 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + - 'c091b0469ab4c04ee9411ef770f32360945f4c53', + 'b18d39bd2ea2d2b508228a9a1d8ae9f7fba32f78', 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f', diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index fbad4d1a..541f6402 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -95,6 +95,11 @@ if (crashpad_is_in_chromium) { "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", ] configs += [ ":gtest_private_config" ] + if (crashpad_is_fuchsia) { + deps = [ + "../fuchsia:zx", + ] + } } static_library("gtest_main") { @@ -112,14 +117,13 @@ if (crashpad_is_in_chromium) { test("gtest_all_test") { sources = [ - "gtest/googletest/test/gtest-death-test_test.cc", - "gtest/googletest/test/gtest-filepath_test.cc", - "gtest/googletest/test/gtest-linked_ptr_test.cc", - "gtest/googletest/test/gtest-message_test.cc", - "gtest/googletest/test/gtest-options_test.cc", - "gtest/googletest/test/gtest-port_test.cc", - "gtest/googletest/test/gtest-printers_test.cc", - "gtest/googletest/test/gtest-test-part_test.cc", + "gtest/googletest/test/googletest-death-test-test.cc", + "gtest/googletest/test/googletest-filepath-test.cc", + "gtest/googletest/test/googletest-message-test.cc", + "gtest/googletest/test/googletest-options-test.cc", + "gtest/googletest/test/googletest-port-test.cc", + "gtest/googletest/test/googletest-printers-test.cc", + "gtest/googletest/test/googletest-test-part-test.cc", "gtest/googletest/test/gtest-typed-test2_test.cc", "gtest/googletest/test/gtest-typed-test_test.cc", "gtest/googletest/test/gtest-typed-test_test.h", @@ -156,7 +160,7 @@ if (crashpad_is_in_chromium) { test("gtest_listener_test") { sources = [ - "gtest/googletest/test/gtest-listener_test.cc", + "gtest/googletest/test/googletest-listener-test.cc", ] deps = [ ":gtest", @@ -174,9 +178,9 @@ if (crashpad_is_in_chromium) { test("gtest_param_test") { sources = [ - "gtest/googletest/test/gtest-param-test2_test.cc", - "gtest/googletest/test/gtest-param-test_test.cc", - "gtest/googletest/test/gtest-param-test_test.h", + "gtest/googletest/test/googletest-param-test-test.cc", + "gtest/googletest/test/googletest-param-test-test.h", + "gtest/googletest/test/googletest-param-test2-test.cc", ] configs -= [ "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", From c56557ae4a4faeea84730c056a0ff11d5759b153 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 27 Nov 2018 10:46:33 -0800 Subject: [PATCH 086/401] [fuchsia][arm64][snapshot] remove NOTREACHEDs we now run this code on arm64 devices in debug mode Bug: crashpad:196 Bug: fuchsia:DX-712 Change-Id: Iea1975c5bd4cab3d503ca371ab731e25962fb255 Tested: /system/test/crashpad_tests on arm64 device in debug mode Reviewed-on: https://chromium-review.googlesource.com/c/1352097 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/fuchsia/system_snapshot_fuchsia.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/snapshot/fuchsia/system_snapshot_fuchsia.cc b/snapshot/fuchsia/system_snapshot_fuchsia.cc index 889817ad..d408dff4 100644 --- a/snapshot/fuchsia/system_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/system_snapshot_fuchsia.cc @@ -73,7 +73,7 @@ uint32_t SystemSnapshotFuchsia::CPURevision() const { #if defined(ARCH_CPU_X86_64) return cpuid_.Revision(); #else - NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196. + // TODO(fuchsia/DX-712): Read actual revision. return 0; #endif } @@ -88,7 +88,7 @@ std::string SystemSnapshotFuchsia::CPUVendor() const { #if defined(ARCH_CPU_X86_64) return cpuid_.Vendor(); #else - NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196. + // TODO(fuchsia/DX-712): Read actual vendor. return std::string(); #endif } @@ -106,7 +106,7 @@ uint32_t SystemSnapshotFuchsia::CPUX86Signature() const { #if defined(ARCH_CPU_X86_64) return cpuid_.Signature(); #else - NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196. + NOTREACHED(); return 0; #endif } @@ -116,7 +116,7 @@ uint64_t SystemSnapshotFuchsia::CPUX86Features() const { #if defined(ARCH_CPU_X86_64) return cpuid_.Features(); #else - NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196. + NOTREACHED(); return 0; #endif } @@ -126,7 +126,7 @@ uint64_t SystemSnapshotFuchsia::CPUX86ExtendedFeatures() const { #if defined(ARCH_CPU_X86_64) return cpuid_.ExtendedFeatures(); #else - NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196. + NOTREACHED(); return 0; #endif } @@ -135,7 +135,7 @@ uint32_t SystemSnapshotFuchsia::CPUX86Leaf7Features() const { #if defined(ARCH_CPU_X86_64) return cpuid_.Leaf7Features(); #else - NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196. + NOTREACHED(); return 0; #endif } @@ -145,7 +145,7 @@ bool SystemSnapshotFuchsia::CPUX86SupportsDAZ() const { #if defined(ARCH_CPU_X86_64) return cpuid_.SupportsDAZ(); #else - NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196. + NOTREACHED(); return false; #endif } @@ -191,7 +191,7 @@ bool SystemSnapshotFuchsia::NXEnabled() const { #if defined(ARCH_CPU_X86_64) return cpuid_.NXEnabled(); #else - NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196. + // TODO(fuchsia/DX-712): Read actual NX bit value. return false; #endif } From 109bece2c3bcc35cbfb1ab3f7981d8ed3cd3f903 Mon Sep 17 00:00:00 2001 From: Tien Mai <tienmai@chromium.org> Date: Mon, 3 Dec 2018 09:28:09 -0500 Subject: [PATCH 087/401] Added support for running crashpad that is embedded inside a dll This code was merged from chromium commit: 6a2d5519c69e195e584055b186789b7f760c9703 Implement crashpad support for GCPW - Implements crashpad support for GCPW installer - Implements crashpad support for the actual credential provider dll and runs the crashpad handler directly in the dll as an entry point Bug: 890348 Change-Id: I5b256b4d6ad8ee7153fd22e4d13f1a1791fa6d65 Reviewed-on: https://chromium-review.googlesource.com/c/1344210 Commit-Queue: Tien Mai <tienmai@chromium.org> Reviewed-by: Greg Thompson <grt@chromium.org> Reviewed-by: Roger Tawa <rogerta@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> Cr-Commit-Position: refs/heads/master@{#611187} Message-Id: Merged from chromium 6a2d5519c69e195e584055b186789b7f760c9703 Reviewed-on: https://chromium-review.googlesource.com/c/1358731 Commit-Queue: Scott Graham <scottmg@chromium.org> --- client/crashpad_client_win.cc | 47 ++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index 8ceded33..0037c1f5 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -15,6 +15,7 @@ #include "client/crashpad_client.h" #include <windows.h> + #include <signal.h> #include <stdint.h> #include <string.h> @@ -73,10 +74,10 @@ base::Lock* g_non_crash_dump_lock; ExceptionInformation g_non_crash_exception_information; enum class StartupState : int { - kNotReady = 0, // This must be value 0 because it is the initial value of a - // global AtomicWord. + kNotReady = 0, // This must be value 0 because it is the initial value of a + // global AtomicWord. kSucceeded = 1, // The CreateProcess() for the handler succeeded. - kFailed = 2, // The handler failed to start. + kFailed = 2, // The handler failed to start. }; // This is a tri-state of type StartupState. It starts at 0 == kNotReady, and @@ -93,8 +94,7 @@ base::subtle::AtomicWord g_handler_startup_state; CRITICAL_SECTION g_critical_section_with_debug_info; void SetHandlerStartupState(StartupState state) { - DCHECK(state == StartupState::kSucceeded || - state == StartupState::kFailed); + DCHECK(state == StartupState::kSucceeded || state == StartupState::kFailed); base::subtle::Acquire_Store(&g_handler_startup_state, static_cast<base::subtle::AtomicWord>(state)); } @@ -476,17 +476,34 @@ bool StartHandlerProcess( } } + // If the embedded crashpad handler is being started via an entry point in a + // DLL (the handler executable is rundll32.exe), then don't pass + // the application name to CreateProcess as this appears to generate an + // invalid command line where the first argument needed by rundll32 is not in + // the correct format as required in: + // https://support.microsoft.com/en-ca/help/164787/info-windows-rundll-and-rundll32-interface + const base::StringPiece16 kRunDll32Exe(L"rundll32.exe"); + bool is_embedded_in_dll = false; + if (data->handler.value().size() >= kRunDll32Exe.size() && + _wcsicmp(data->handler.value() + .substr(data->handler.value().size() - kRunDll32Exe.size()) + .c_str(), + kRunDll32Exe.data()) == 0) { + is_embedded_in_dll = true; + } + PROCESS_INFORMATION process_info; - rv = CreateProcess(data->handler.value().c_str(), - &command_line[0], - nullptr, - nullptr, - true, - creation_flags, - nullptr, - nullptr, - &startup_info.StartupInfo, - &process_info); + rv = CreateProcess( + is_embedded_in_dll ? nullptr : data->handler.value().c_str(), + &command_line[0], + nullptr, + nullptr, + true, + creation_flags, + nullptr, + nullptr, + &startup_info.StartupInfo, + &process_info); if (!rv) { PLOG(ERROR) << "CreateProcess"; return false; From 1a9209b581b9291e17e64f05134b1e77ea6398b2 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Wed, 5 Dec 2018 19:58:48 -0800 Subject: [PATCH 088/401] [fuchsia] actually clean up lock file in release mode * the call to LoggingRemoveFile wrapped ina DCHECK is actually only executed in debug mode :-( * found the issue using zxdb! Bug: fuchsia:DX-344 Bug: crashpad:217, crashpad:196 Change-Id: I5332a17ccffd94b9bad8c61831adb797bd53a13d Tested:`crasher` on device Reviewed-on: https://chromium-review.googlesource.com/c/1364452 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- client/settings.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/settings.cc b/client/settings.cc index 20bd2581..f6db78db 100644 --- a/client/settings.cc +++ b/client/settings.cc @@ -63,7 +63,8 @@ void Settings::ScopedLockedFileHandle::Destroy() { CheckedCloseFile(handle_); } if (!lockfile_path_.empty()) { - DCHECK(LoggingRemoveFile(lockfile_path_)); + const bool success = LoggingRemoveFile(lockfile_path_); + DCHECK(success); } } From 9b6dde910185ef8c9b0c3f11f34f62d788cc58b7 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Thu, 6 Dec 2018 14:23:20 -0800 Subject: [PATCH 089/401] [fuchsia] remove Fuchsia-specific code in MoveFileOrDirectory ZX-1729 has been fixed upstream Change-Id: Ia9c55b13169db650eb4ca0562434ae19a6f44eaf Reviewed-on: https://chromium-review.googlesource.com/c/1366638 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- util/file/filesystem_posix.cc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/util/file/filesystem_posix.cc b/util/file/filesystem_posix.cc index c2234dae..b1f19f62 100644 --- a/util/file/filesystem_posix.cc +++ b/util/file/filesystem_posix.cc @@ -65,14 +65,6 @@ bool LoggingCreateDirectory(const base::FilePath& path, bool MoveFileOrDirectory(const base::FilePath& source, const base::FilePath& dest) { -#if defined(OS_FUCHSIA) - // Fuchsia fails and sets errno to EINVAL if source and dest are the same. - // Upstream bug is ZX-1729. - if (!source.empty() && source == dest) { - return true; - } -#endif // OS_FUCHSIA - if (rename(source.value().c_str(), dest.value().c_str()) != 0) { PLOG(ERROR) << "rename " << source.value().c_str() << ", " << dest.value().c_str(); From 761c6fe8be0e18da9bb13b8dbdb57b4bf7be054b Mon Sep 17 00:00:00 2001 From: Tom Tan <Tom.Tan@microsoft.com> Date: Wed, 12 Dec 2018 12:58:24 -0800 Subject: [PATCH 090/401] Add Windows ARM64 support to Chromium crashpad Bug: chromium:893460 Change-Id: Ifbeb6f937a6b96c77b02dcf8afe492c5bc617435 Reviewed-on: https://chromium-review.googlesource.com/c/1347773 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_win.cc | 13 ++--- snapshot/win/cpu_context_win.cc | 40 ++++++++++++++-- snapshot/win/cpu_context_win.h | 23 ++++++--- .../crashpad_snapshot_test_crashing_child.cc | 10 ++-- ...pad_snapshot_test_dump_without_crashing.cc | 9 ++-- snapshot/win/exception_snapshot_win.cc | 33 +++++++++---- snapshot/win/exception_snapshot_win.h | 8 ++-- snapshot/win/process_reader_win_test.cc | 8 +--- snapshot/win/process_snapshot_win.cc | 3 +- snapshot/win/system_snapshot_win.cc | 48 +++++++++++++++++++ snapshot/win/system_snapshot_win_test.cc | 4 ++ snapshot/win/thread_snapshot_win.cc | 16 +++++-- snapshot/win/thread_snapshot_win.h | 8 +++- third_party/zlib/BUILD.gn | 6 +++ util/BUILD.gn | 14 ++++-- util/misc/capture_context_test_util_win.cc | 9 ++-- util/net/http_transport_win.cc | 2 + util/util.gyp | 1 + util/win/context_wrappers.h | 40 ++++++++++++++++ util/win/safe_terminate_process_test.cc | 3 ++ 20 files changed, 229 insertions(+), 69 deletions(-) create mode 100644 util/win/context_wrappers.h diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index 0037c1f5..143dc4f1 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -36,6 +36,7 @@ #include "util/misc/random_string.h" #include "util/win/address_types.h" #include "util/win/command_line.h" +#include "util/win/context_wrappers.h" #include "util/win/critical_section_with_debug_info.h" #include "util/win/get_function.h" #include "util/win/handle.h" @@ -187,11 +188,7 @@ void HandleAbortSignal(int signum) { EXCEPTION_RECORD record = {}; record.ExceptionCode = STATUS_FATAL_APP_EXIT; record.ExceptionFlags = EXCEPTION_NONCONTINUABLE; -#if defined(ARCH_CPU_64_BITS) - record.ExceptionAddress = reinterpret_cast<void*>(context.Rip); -#else - record.ExceptionAddress = reinterpret_cast<void*>(context.Eip); -#endif // ARCH_CPU_64_BITS + record.ExceptionAddress = ProgramCounterFromCONTEXT(&context); EXCEPTION_POINTERS exception_pointers; exception_pointers.ContextRecord = &context; @@ -773,11 +770,7 @@ void CrashpadClient::DumpWithoutCrash(const CONTEXT& context) { constexpr uint32_t kSimulatedExceptionCode = 0x517a7ed; EXCEPTION_RECORD record = {}; record.ExceptionCode = kSimulatedExceptionCode; -#if defined(ARCH_CPU_64_BITS) - record.ExceptionAddress = reinterpret_cast<void*>(context.Rip); -#else - record.ExceptionAddress = reinterpret_cast<void*>(context.Eip); -#endif // ARCH_CPU_64_BITS + record.ExceptionAddress = ProgramCounterFromCONTEXT(&context); exception_pointers.ExceptionRecord = &record; diff --git a/snapshot/win/cpu_context_win.cc b/snapshot/win/cpu_context_win.cc index 1a76c6d9..db2e8036 100644 --- a/snapshot/win/cpu_context_win.cc +++ b/snapshot/win/cpu_context_win.cc @@ -126,7 +126,13 @@ void CommonInitializeX86Context(const T& context, CPUContextX86* out) { } // namespace -#if defined(ARCH_CPU_64_BITS) +#if defined(ARCH_CPU_X86) + +void InitializeX86Context(const CONTEXT& context, CPUContextX86* out) { + CommonInitializeX86Context(context, out); +} + +#elif defined(ARCH_CPU_X86_64) void InitializeX86Context(const WOW64_CONTEXT& context, CPUContextX86* out) { CommonInitializeX86Context(context, out); @@ -192,12 +198,36 @@ void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out) { } } -#else // ARCH_CPU_64_BITS +#elif defined(ARCH_CPU_ARM64) -void InitializeX86Context(const CONTEXT& context, CPUContextX86* out) { - CommonInitializeX86Context(context, 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; + } + + if (HasContextPart(context, CONTEXT_INTEGER)) { + 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)); + } + + if (HasContextPart(context, CONTEXT_FLOATING_POINT)) { + static_assert(sizeof(out->fpsimd) == sizeof(context.V), + "types must be equivalent"); + memcpy(&out->fpsimd, &context.V, sizeof(out->fpsimd)); + } } -#endif // ARCH_CPU_64_BITS +#else +#error Unsupported Windows Arch +#endif // ARCH_CPU_X86 } // namespace crashpad diff --git a/snapshot/win/cpu_context_win.h b/snapshot/win/cpu_context_win.h index a384ccb3..9718f49c 100644 --- a/snapshot/win/cpu_context_win.h +++ b/snapshot/win/cpu_context_win.h @@ -23,8 +23,17 @@ namespace crashpad { struct CPUContextX86; struct CPUContextX86_64; +struct CPUContextARM64; -#if defined(ARCH_CPU_64_BITS) || DOXYGEN +#if defined(ARCH_CPU_X86) || DOXYGEN + +//! \brief Initializes a CPUContextX86 structure from a native context structure +//! on Windows. +void InitializeX86Context(const CONTEXT& context, CPUContextX86* out); + +#endif // ARCH_CPU_X86 + +#if defined(ARCH_CPU_X86_64) || DOXYGEN //! \brief Initializes a CPUContextX86 structure from a native context structure //! on Windows. @@ -34,13 +43,15 @@ void InitializeX86Context(const WOW64_CONTEXT& context, CPUContextX86* out); //! structure on Windows. void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out); -#else // ARCH_CPU_64_BITS +#endif // ARCH_CPU_X86_64 -//! \brief Initializes a CPUContextX86 structure from a native context structure -//! on Windows. -void InitializeX86Context(const CONTEXT& context, CPUContextX86* out); +#if defined(ARCH_CPU_ARM64) || DOXYGEN -#endif // ARCH_CPU_64_BITS +//! \brief Initializes a CPUContextARM64 structure from a native context +//! structure on Windows. +void InitializeARM64Context(const CONTEXT& context, CPUContextARM64* out); + +#endif // ARCH_CPU_ARM64 } // namespace crashpad diff --git a/snapshot/win/crashpad_snapshot_test_crashing_child.cc b/snapshot/win/crashpad_snapshot_test_crashing_child.cc index 759cc138..cc1369e6 100644 --- a/snapshot/win/crashpad_snapshot_test_crashing_child.cc +++ b/snapshot/win/crashpad_snapshot_test_crashing_child.cc @@ -16,10 +16,10 @@ #include <windows.h> #include "base/logging.h" -#include "build/build_config.h" #include "client/crashpad_client.h" #include "util/misc/capture_context.h" #include "util/win/address_types.h" +#include "util/win/context_wrappers.h" int wmain(int argc, wchar_t* argv[]) { CHECK_EQ(argc, 2); @@ -32,11 +32,9 @@ int wmain(int argc, wchar_t* argv[]) { CONTEXT context; crashpad::CaptureContext(&context); -#if defined(ARCH_CPU_64_BITS) - crashpad::WinVMAddress break_address = context.Rip; -#else - crashpad::WinVMAddress break_address = context.Eip; -#endif + crashpad::WinVMAddress break_address = + reinterpret_cast<crashpad::WinVMAddress>( + crashpad::ProgramCounterFromCONTEXT(&context)); // This does not used CheckedWriteFile() because at high optimization // settings, a lot of logging code can be inlined, causing there to be a large diff --git a/snapshot/win/crashpad_snapshot_test_dump_without_crashing.cc b/snapshot/win/crashpad_snapshot_test_dump_without_crashing.cc index e2c524ae..cc441a40 100644 --- a/snapshot/win/crashpad_snapshot_test_dump_without_crashing.cc +++ b/snapshot/win/crashpad_snapshot_test_dump_without_crashing.cc @@ -20,6 +20,7 @@ #include "client/simulate_crash.h" #include "util/misc/capture_context.h" #include "util/win/address_types.h" +#include "util/win/context_wrappers.h" int wmain(int argc, wchar_t* argv[]) { CHECK_EQ(argc, 2); @@ -32,11 +33,9 @@ int wmain(int argc, wchar_t* argv[]) { CONTEXT context; crashpad::CaptureContext(&context); -#if defined(ARCH_CPU_64_BITS) - crashpad::WinVMAddress break_address = context.Rip; -#else - crashpad::WinVMAddress break_address = context.Eip; -#endif + crashpad::WinVMAddress break_address = + reinterpret_cast<crashpad::WinVMAddress>( + crashpad::ProgramCounterFromCONTEXT(&context)); // This does not used CheckedWriteFile() because at high optimization // settings, a lot of logging code can be inlined, causing there to be a large diff --git a/snapshot/win/exception_snapshot_win.cc b/snapshot/win/exception_snapshot_win.cc index cba6f121..e8ea1e89 100644 --- a/snapshot/win/exception_snapshot_win.cc +++ b/snapshot/win/exception_snapshot_win.cc @@ -28,22 +28,13 @@ namespace internal { namespace { +#if defined(ARCH_CPU_X86_FAMILY) #if defined(ARCH_CPU_32_BITS) using Context32 = CONTEXT; #elif defined(ARCH_CPU_64_BITS) using Context32 = WOW64_CONTEXT; #endif -#if defined(ARCH_CPU_64_BITS) -void NativeContextToCPUContext64(const CONTEXT& context_record, - CPUContext* context, - CPUContextUnion* context_union) { - context->architecture = kCPUArchitectureX86_64; - context->x86_64 = &context_union->x86_64; - InitializeX64Context(context_record, context->x86_64); -} -#endif - void NativeContextToCPUContext32(const Context32& context_record, CPUContext* context, CPUContextUnion* context_union) { @@ -51,6 +42,25 @@ void NativeContextToCPUContext32(const Context32& context_record, context->x86 = &context_union->x86; InitializeX86Context(context_record, context->x86); } +#endif // ARCH_CPU_X86_FAMILY + +#if defined(ARCH_CPU_64_BITS) +void NativeContextToCPUContext64(const CONTEXT& context_record, + CPUContext* context, + CPUContextUnion* context_union) { +#if defined(ARCH_CPU_X86_64) + context->architecture = kCPUArchitectureX86_64; + context->x86_64 = &context_union->x86_64; + InitializeX64Context(context_record, context->x86_64); +#elif defined(ARCH_CPU_ARM64) + context->architecture = kCPUArchitectureARM64; + context->arm64 = &context_union->arm64; + InitializeARM64Context(context_record, context->arm64); +#else +#error Unsupported Windows 64-bit Arch +#endif +} +#endif } // namespace @@ -106,6 +116,8 @@ bool ExceptionSnapshotWin::Initialize( } } #endif + +#if !defined(ARCH_CPU_ARM64) if (!is_64_bit) { if (!InitializeFromExceptionPointers<EXCEPTION_RECORD32, process_types::EXCEPTION_POINTERS32>( @@ -116,6 +128,7 @@ bool ExceptionSnapshotWin::Initialize( return false; } } +#endif CaptureMemoryDelegateWin capture_memory_delegate( process_reader, *thread, &extra_memory_, nullptr); diff --git a/snapshot/win/exception_snapshot_win.h b/snapshot/win/exception_snapshot_win.h index f6e29d9f..1eed538c 100644 --- a/snapshot/win/exception_snapshot_win.h +++ b/snapshot/win/exception_snapshot_win.h @@ -38,12 +38,14 @@ namespace internal { class MemorySnapshotWin; -#if defined(ARCH_CPU_X86_FAMILY) union CPUContextUnion { +#if defined(ARCH_CPU_X86_FAMILY) CPUContextX86 x86; CPUContextX86_64 x86_64; -}; +#elif defined(ARCH_CPU_ARM64) + CPUContextARM64 arm64; #endif +}; class ExceptionSnapshotWin final : public ExceptionSnapshot { public: @@ -91,9 +93,7 @@ class ExceptionSnapshotWin final : public ExceptionSnapshot { CPUContext* context, CPUContextUnion* context_union)); -#if defined(ARCH_CPU_X86_FAMILY) CPUContextUnion context_union_; -#endif CPUContext context_; std::vector<uint64_t> codes_; std::vector<std::unique_ptr<internal::MemorySnapshotWin>> extra_memory_; diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index 0f122fbd..b0601e8b 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -22,6 +22,7 @@ #include "util/misc/from_pointer_cast.h" #include "util/synchronization/semaphore.h" #include "util/thread/thread.h" +#include "util/win/context_wrappers.h" #include "util/win/scoped_process_suspend.h" namespace crashpad { @@ -106,12 +107,7 @@ TEST(ProcessReaderWin, SelfOneThread) { ASSERT_GE(threads.size(), 1u); EXPECT_EQ(threads[0].id, GetCurrentThreadId()); -#if defined(ARCH_CPU_64_BITS) - EXPECT_NE(threads[0].context.native.Rip, 0u); -#else - EXPECT_NE(threads[0].context.native.Eip, 0u); -#endif - + EXPECT_NE(ProgramCounterFromCONTEXT(&threads[0].context.native), nullptr); EXPECT_EQ(threads[0].suspend_count, 0u); } diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index af6fe4d2..94dd22b5 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -23,6 +23,7 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "util/misc/from_pointer_cast.h" #include "util/misc/time.h" #include "util/win/nt_internals.h" @@ -276,7 +277,7 @@ void ProcessSnapshotWin::InitializeUnloadedModules() { // and 32-reading-32, so at the moment, we simply do not retrieve unloaded // modules for 64-reading-32. See https://crashpad.chromium.org/bug/89. -#if defined(ARCH_CPU_X86_64) +#if defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARM64) if (!process_reader_.Is64Bit()) { LOG(ERROR) << "reading unloaded modules across bitness not currently supported"; diff --git a/snapshot/win/system_snapshot_win.cc b/snapshot/win/system_snapshot_win.cc index 74f34a7e..2a93baaf 100644 --- a/snapshot/win/system_snapshot_win.cc +++ b/snapshot/win/system_snapshot_win.cc @@ -26,6 +26,7 @@ #include "base/numerics/safe_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" #include "util/win/module_version.h" namespace crashpad { @@ -125,13 +126,20 @@ void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) { CPUArchitecture SystemSnapshotWin::GetCPUArchitecture() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); +#if defined(ARCH_CPU_X86_FAMILY) return process_reader_->Is64Bit() ? kCPUArchitectureX86_64 : kCPUArchitectureX86; +#elif defined(ARCH_CPU_ARM64) + return kCPUArchitectureARM64; +#else +#error Unsupported Windows Arch +#endif } uint32_t SystemSnapshotWin::CPURevision() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); +#if defined(ARCH_CPU_X86_FAMILY) uint32_t raw = CPUX86Signature(); uint8_t stepping = raw & 0xf; uint8_t model = (raw & 0xf0) >> 4; @@ -149,6 +157,13 @@ uint32_t SystemSnapshotWin::CPURevision() const { uint16_t adjusted_family = family + extended_family; uint8_t adjusted_model = model + (extended_model << 4); return (adjusted_family << 16) | (adjusted_model << 8) | stepping; +#elif defined(ARCH_CPU_ARM64) + // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30 + // This is the same as SystemSnapshotLinux::CPURevision. + return 0; +#else +#error Unsupported Windows Arch +#endif } uint8_t SystemSnapshotWin::CPUCount() const { @@ -166,6 +181,7 @@ uint8_t SystemSnapshotWin::CPUCount() const { std::string SystemSnapshotWin::CPUVendor() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); +#if defined(ARCH_CPU_X86_FAMILY) int cpu_info[4]; __cpuid(cpu_info, 0); char vendor[12]; @@ -173,6 +189,13 @@ std::string SystemSnapshotWin::CPUVendor() const { *reinterpret_cast<int*>(vendor + 4) = cpu_info[3]; *reinterpret_cast<int*>(vendor + 8) = cpu_info[2]; return std::string(vendor, sizeof(vendor)); +#elif defined(ARCH_CPU_ARM64) + // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30 + // This is the same as SystemSnapshotLinux::CPURevision. + return std::string(); +#else +#error Unsupported Windows Arch +#endif } void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz, @@ -212,36 +235,52 @@ void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz, uint32_t SystemSnapshotWin::CPUX86Signature() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); +#if defined(ARCH_CPU_X86_FAMILY) int cpu_info[4]; // We will never run on any processors that don't support at least function 1. __cpuid(cpu_info, 1); return cpu_info[0]; +#else + NOTREACHED(); + return 0; +#endif } uint64_t SystemSnapshotWin::CPUX86Features() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); +#if defined(ARCH_CPU_X86_FAMILY) int cpu_info[4]; // We will never run on any processors that don't support at least function 1. __cpuid(cpu_info, 1); return (static_cast<uint64_t>(cpu_info[2]) << 32) | static_cast<uint64_t>(cpu_info[3]); +#else + NOTREACHED(); + return 0; +#endif } uint64_t SystemSnapshotWin::CPUX86ExtendedFeatures() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); +#if defined(ARCH_CPU_X86_FAMILY) int cpu_info[4]; // We will never run on any processors that don't support at least extended // function 1. __cpuid(cpu_info, 0x80000001); return (static_cast<uint64_t>(cpu_info[2]) << 32) | static_cast<uint64_t>(cpu_info[3]); +#else + NOTREACHED(); + return 0; +#endif } uint32_t SystemSnapshotWin::CPUX86Leaf7Features() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); +#if defined(ARCH_CPU_X86_FAMILY) int cpu_info[4]; // Make sure leaf 7 can be called. @@ -251,11 +290,16 @@ uint32_t SystemSnapshotWin::CPUX86Leaf7Features() const { __cpuidex(cpu_info, 7, 0); return cpu_info[1]; +#else + NOTREACHED(); + return 0; +#endif } bool SystemSnapshotWin::CPUX86SupportsDAZ() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); +#if defined(ARCH_CPU_X86_FAMILY) // The correct way to check for denormals-as-zeros (DAZ) support is to examine // mxcsr mask, which can be done with fxsave. See Intel Software Developer's // Manual, Volume 1: Basic Architecture (253665-051), 11.6.3 "Checking for the @@ -277,6 +321,10 @@ bool SystemSnapshotWin::CPUX86SupportsDAZ() const { // Test the DAZ bit. return (mxcsr_mask & (1 << 6)) != 0; +#else + NOTREACHED(); + return 0; +#endif } SystemSnapshot::OperatingSystem SystemSnapshotWin::GetOperatingSystem() const { diff --git a/snapshot/win/system_snapshot_win_test.cc b/snapshot/win/system_snapshot_win_test.cc index c87a6a6a..80659930 100644 --- a/snapshot/win/system_snapshot_win_test.cc +++ b/snapshot/win/system_snapshot_win_test.cc @@ -60,6 +60,10 @@ TEST_F(SystemSnapshotWinTest, GetCPUArchitecture) { EXPECT_EQ(cpu_architecture, kCPUArchitectureX86); #elif defined(ARCH_CPU_X86_64) EXPECT_EQ(cpu_architecture, kCPUArchitectureX86_64); +#elif defined(ARCH_CPU_ARM64) + EXPECT_EQ(cpu_architecture, kCPUArchitectureARM64); +#else +#error Unsupported Windows Arch #endif } diff --git a/snapshot/win/thread_snapshot_win.cc b/snapshot/win/thread_snapshot_win.cc index 3b927f92..f381a4b9 100644 --- a/snapshot/win/thread_snapshot_win.cc +++ b/snapshot/win/thread_snapshot_win.cc @@ -63,7 +63,11 @@ bool ThreadSnapshotWin::Initialize( teb_.Initialize(process_reader, 0, 0); } -#if defined(ARCH_CPU_X86_64) +#if defined(ARCH_CPU_X86) + context_.architecture = kCPUArchitectureX86; + context_.x86 = &context_union_.x86; + InitializeX86Context(process_reader_thread.context.native, context_.x86); +#elif defined(ARCH_CPU_X86_64) if (process_reader->Is64Bit()) { context_.architecture = kCPUArchitectureX86_64; context_.x86_64 = &context_union_.x86_64; @@ -73,11 +77,13 @@ bool ThreadSnapshotWin::Initialize( context_.x86 = &context_union_.x86; InitializeX86Context(process_reader_thread.context.wow64, context_.x86); } +#elif defined(ARCH_CPU_ARM64) + context_.architecture = kCPUArchitectureARM64; + context_.arm64 = &context_union_.arm64; + InitializeARM64Context(process_reader_thread.context.native, context_.arm64); #else - context_.architecture = kCPUArchitectureX86; - context_.x86 = &context_union_.x86; - InitializeX86Context(process_reader_thread.context.native, context_.x86); -#endif // ARCH_CPU_X86_64 +#error Unsupported Windows Arch +#endif // ARCH_CPU_X86 CaptureMemoryDelegateWin capture_memory_delegate( process_reader, diff --git a/snapshot/win/thread_snapshot_win.h b/snapshot/win/thread_snapshot_win.h index 273fc7f0..63465803 100644 --- a/snapshot/win/thread_snapshot_win.h +++ b/snapshot/win/thread_snapshot_win.h @@ -71,12 +71,16 @@ class ThreadSnapshotWin final : public ThreadSnapshot { std::vector<const MemorySnapshot*> ExtraMemory() const override; private: -#if defined(ARCH_CPU_X86_FAMILY) union { +#if defined(ARCH_CPU_X86_FAMILY) CPUContextX86 x86; CPUContextX86_64 x86_64; - } context_union_; +#elif defined(ARCH_CPU_ARM64) + CPUContextARM64 arm64; +#else +#error Unsupported Windows Arch #endif + } context_union_; CPUContext context_; MemorySnapshotWin stack_; MemorySnapshotWin teb_; diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn index c436bc87..f84b8baf 100644 --- a/third_party/zlib/BUILD.gn +++ b/third_party/zlib/BUILD.gn @@ -91,6 +91,12 @@ if (zlib_source == "external") { "/wd4324", # structure was padded due to alignment specifier "/wd4702", # unreachable code ] + if (current_cpu == "arm64" && !crashpad_is_clang) { + # Select code path for clang in zlib to avoid using MSVC x86/x64 + # intrinsics for Windows ARM64. + # TODO: https://crashpad.chromium.org/bug/267 + defines += [ "__clang__" ] + } } else { defines += [ "HAVE_HIDDEN", diff --git a/util/BUILD.gn b/util/BUILD.gn index 9f62e6aa..9f47a41b 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -341,6 +341,7 @@ static_library("util") { "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", @@ -390,10 +391,15 @@ static_library("util") { # TODO(thakis): Use the .asm file in cross builds somehow, # https://crbug.com/762167. if (host_os == "win") { - sources += [ - "misc/capture_context_win.asm", - "win/safe_terminate_process.asm", - ] + if (current_cpu != "arm64") { + sources += [ + "misc/capture_context_win.asm", + "win/safe_terminate_process.asm", + ] + } else { + # TODO: Add assembly code of CaptureContext for Windows ARM64. + sources += [ "misc/capture_context_broken.cc" ] + } } else { sources += [ "misc/capture_context_broken.cc", diff --git a/util/misc/capture_context_test_util_win.cc b/util/misc/capture_context_test_util_win.cc index 239beacd..092449ef 100644 --- a/util/misc/capture_context_test_util_win.cc +++ b/util/misc/capture_context_test_util_win.cc @@ -13,6 +13,7 @@ // limitations under the License. #include "util/misc/capture_context_test_util.h" +#include "util/win/context_wrappers.h" #include "base/macros.h" #include "gtest/gtest.h" @@ -95,11 +96,7 @@ void SanityCheckContext(const NativeCPUContext& context) { } uintptr_t ProgramCounterFromContext(const NativeCPUContext& context) { -#if defined(ARCH_CPU_X86) - return context.Eip; -#elif defined(ARCH_CPU_X86_64) - return context.Rip; -#endif + return reinterpret_cast<uintptr_t>(ProgramCounterFromCONTEXT(&context)); } uintptr_t StackPointerFromContext(const NativeCPUContext& context) { @@ -107,6 +104,8 @@ uintptr_t StackPointerFromContext(const NativeCPUContext& context) { return context.Esp; #elif defined(ARCH_CPU_X86_64) return context.Rsp; +#elif defined(ARCH_CPU_ARM64) + return context.Sp; #endif } diff --git a/util/net/http_transport_win.cc b/util/net/http_transport_win.cc index 2919bc11..f86e4594 100644 --- a/util/net/http_transport_win.cc +++ b/util/net/http_transport_win.cc @@ -65,6 +65,8 @@ std::string UserAgent() { user_agent.append("x86"); #elif defined(ARCH_CPU_X86_64) user_agent.append("x64"); +#elif defined(ARCH_CPU_ARM64) + user_agent.append("arm64"); #else #error Port #endif diff --git a/util/util.gyp b/util/util.gyp index 1ffb752c..a8ed59e6 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -246,6 +246,7 @@ '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', diff --git a/util/win/context_wrappers.h b/util/win/context_wrappers.h new file mode 100644 index 00000000..5d9b1838 --- /dev/null +++ b/util/win/context_wrappers.h @@ -0,0 +1,40 @@ +// Copyright 2018 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_CONTEXT_WRAPPERS_H_ +#define CRASHPAD_UTIL_WIN_CONTEXT_WRAPPERS_H_ + +#include <windows.h> + +#include "build/build_config.h" + +namespace crashpad { + +//! \brief Retrieve program counter from `CONTEXT` structure for different +//! architectures supported by Windows. +inline void* ProgramCounterFromCONTEXT(const CONTEXT* context) { +#if defined(ARCH_CPU_X86) + return reinterpret_cast<void*>(context->Eip); +#elif defined(ARCH_CPU_X86_64) + return reinterpret_cast<void*>(context->Rip); +#elif defined(ARCH_CPU_ARM64) + return reinterpret_cast<void*>(context->Pc); +#else +#error Unsupported Windows Arch +#endif // ARCH_CPU_X86 +} + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_WIN_CONTEXT_WRAPPERS_H_ diff --git a/util/win/safe_terminate_process_test.cc b/util/win/safe_terminate_process_test.cc index 3aba1591..f9db161b 100644 --- a/util/win/safe_terminate_process_test.cc +++ b/util/win/safe_terminate_process_test.cc @@ -91,6 +91,8 @@ class ScopedExecutablePatch { DISALLOW_COPY_AND_ASSIGN(ScopedExecutablePatch); }; +// SafeTerminateProcess is calling convention specific only for x86. +#if defined(ARCH_CPU_X86_FAMILY) TEST(SafeTerminateProcess, PatchBadly) { // This is a test of SafeTerminateProcess(), but it doesn’t actually terminate // anything. Instead, it works with a process handle for the current process @@ -161,6 +163,7 @@ TEST(SafeTerminateProcess, PatchBadly) { EXPECT_FALSE(SafeTerminateProcess(process, 0)); EXPECT_EQ(GetLastError(), static_cast<DWORD>(ERROR_ACCESS_DENIED)); } +#endif // ARCH_CPU_X86_FAMILY TEST(SafeTerminateProcess, TerminateChild) { base::FilePath child_executable = From 067f7ddebf65a7be2fc8208eddf274af05892e38 Mon Sep 17 00:00:00 2001 From: Eric Astor <epastor@google.com> Date: Thu, 13 Dec 2018 13:18:46 -0500 Subject: [PATCH 091/401] Fixes a potential testing crash. Crashpad client testing no longer addresses an element of a possibly- empty array. Change-Id: I434b4b8c462894d8241b810973e1b4a87d1851ba Reviewed-on: https://chromium-review.googlesource.com/c/1376375 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_linux_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index 4c5bf4de..1f80d25f 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -189,7 +189,7 @@ class StartHandlerAtCrashTest : public MultiprocessExec { reports.clear(); ASSERT_EQ(database->GetPendingReports(&reports), CrashReportDatabase::kNoError); - EXPECT_EQ(reports.size(), 1u); + ASSERT_EQ(reports.size(), 1u); std::unique_ptr<const CrashReportDatabase::UploadReport> report; ASSERT_EQ(database->GetReportForUploading(reports[0].uuid, &report), From 8b6f158d20cbc15d04dd0f25da9d820b7d6c4fe9 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 14 Dec 2018 13:17:43 -0800 Subject: [PATCH 092/401] fuchsia: Include address space information in process snapshot This plumbs some of the ZX_INFO_PROCESS_MAPS information out into MINIDUMP_MEMORY_INFO. The mapping loses some information that Zircon provides, and some of the data that Windows would provide isn't available (for example, AllocationProtect). But this gives a general idea of the memory layout of the process to check for bad pointers, etc. when inspecting crashes. Bug: fuchsia:DX-615 Change-Id: I2d7c02be0996672253cf0b1eb6a60b0a55e6033b Reviewed-on: https://chromium-review.googlesource.com/c/1377089 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/BUILD.gn | 7 +- snapshot/fuchsia/memory_map_fuchsia.h | 4 + .../memory_map_region_snapshot_fuchsia.cc | 83 +++++++++++ .../memory_map_region_snapshot_fuchsia.h | 39 +++++ snapshot/fuchsia/process_reader_fuchsia.h | 3 + snapshot/fuchsia/process_snapshot_fuchsia.cc | 13 +- snapshot/fuchsia/process_snapshot_fuchsia.h | 3 + .../fuchsia/process_snapshot_fuchsia_test.cc | 141 ++++++++++++++++++ 8 files changed, 291 insertions(+), 2 deletions(-) create mode 100644 snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc create mode 100644 snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h create mode 100644 snapshot/fuchsia/process_snapshot_fuchsia_test.cc diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index cbc853ad..9fe8582a 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -200,6 +200,8 @@ static_library("snapshot") { "fuchsia/exception_snapshot_fuchsia.h", "fuchsia/memory_map_fuchsia.cc", "fuchsia/memory_map_fuchsia.h", + "fuchsia/memory_map_region_snapshot_fuchsia.cc", + "fuchsia/memory_map_region_snapshot_fuchsia.h", "fuchsia/process_reader_fuchsia.cc", "fuchsia/process_reader_fuchsia.h", "fuchsia/process_snapshot_fuchsia.cc", @@ -384,7 +386,10 @@ source_set("snapshot_test") { } if (crashpad_is_fuchsia) { - sources += [ "fuchsia/process_reader_fuchsia_test.cc" ] + sources += [ + "fuchsia/process_reader_fuchsia_test.cc", + "fuchsia/process_snapshot_fuchsia_test.cc", + ] } # public_configs isn’t quite right. snapshot_test_link sets ldflags, and diff --git a/snapshot/fuchsia/memory_map_fuchsia.h b/snapshot/fuchsia/memory_map_fuchsia.h index c3511200..cdbdb179 100644 --- a/snapshot/fuchsia/memory_map_fuchsia.h +++ b/snapshot/fuchsia/memory_map_fuchsia.h @@ -46,6 +46,10 @@ class MemoryMapFuchsia { //! will be filled out, otherwise `false` and \a map will be unchanged. bool FindMappingForAddress(zx_vaddr_t address, zx_info_maps_t* map) const; + //! \brief Get a vector of `zx_info_maps_t` representing the memory map for + //! this process. + const std::vector<zx_info_maps_t>& Entries() const { return map_entries_; } + private: std::vector<zx_info_maps_t> map_entries_; InitializationStateDcheck initialized_; diff --git a/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc b/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc new file mode 100644 index 00000000..cf2ee61d --- /dev/null +++ b/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc @@ -0,0 +1,83 @@ +// Copyright 2018 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/fuchsia/memory_map_region_snapshot_fuchsia.h" + +#include "base/logging.h" + +namespace crashpad { +namespace internal { + +namespace { + +// Maps from bitwise OR of Zircon's flags to enumerated Windows version. +uint32_t MmuFlagsToProtectFlags(zx_vm_option_t flags) { + // These bits are currently the lowest 3 of zx_vm_option_t. They're used to + // index into a mapping array, so make sure that we notice if they change + // values. + static_assert( + ZX_VM_PERM_READ == 1 && ZX_VM_PERM_WRITE == 2 && ZX_VM_PERM_EXECUTE == 4, + "table below will need fixing"); + + // The entries set to zero don't have good corresponding Windows minidump + // names. They also aren't currently supported by the mapping syscall on + // Zircon, so DCHECK that they don't happen in practice. EXECUTE-only also + // cannot currently happen, but as that has a good mapping to the Windows + // value, leave it in place in case it's supported by the syscall in the + // future. + static constexpr uint32_t mapping[] = { + /* --- */ PAGE_NOACCESS, + /* --r */ PAGE_READONLY, + /* -w- */ 0, + /* -wr */ PAGE_READWRITE, + /* x-- */ PAGE_EXECUTE, + /* x-r */ PAGE_EXECUTE_READ, + /* xw- */ 0, + /* xwr */ PAGE_EXECUTE_READWRITE, + }; + + const uint32_t index = + flags & (ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE); + DCHECK_LT(index, arraysize(mapping)); + + const uint32_t protect_flags = mapping[index]; + DCHECK_NE(protect_flags, 0u); + return protect_flags; +} + +} // namespace + +MemoryMapRegionSnapshotFuchsia::MemoryMapRegionSnapshotFuchsia( + const zx_info_maps_t& info_map) + : memory_info_() { + DCHECK_EQ(info_map.type, ZX_INFO_MAPS_TYPE_MAPPING); + + memory_info_.BaseAddress = info_map.base; + memory_info_.AllocationBase = info_map.base; + memory_info_.RegionSize = info_map.size; + memory_info_.State = MEM_COMMIT; + memory_info_.Protect = memory_info_.AllocationProtect = + MmuFlagsToProtectFlags(info_map.u.mapping.mmu_flags); + memory_info_.Type = MEM_MAPPED; +} + +MemoryMapRegionSnapshotFuchsia::~MemoryMapRegionSnapshotFuchsia() {} + +const MINIDUMP_MEMORY_INFO& +MemoryMapRegionSnapshotFuchsia::AsMinidumpMemoryInfo() const { + return memory_info_; +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h b/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h new file mode 100644 index 00000000..37f7a1a7 --- /dev/null +++ b/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h @@ -0,0 +1,39 @@ +// Copyright 2018 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_FUCHSIA_MEMORY_MAP_REGION_SNAPSHOT_FUCHSIA_H_ +#define CRASHPAD_SNAPSHOT_FUCHSIA_MEMORY_MAP_REGION_SNAPSHOT_FUCHSIA_H_ + +#include "snapshot/memory_map_region_snapshot.h" + +#include <zircon/syscalls/object.h> + +namespace crashpad { +namespace internal { + +class MemoryMapRegionSnapshotFuchsia : public MemoryMapRegionSnapshot { + public: + explicit MemoryMapRegionSnapshotFuchsia(const zx_info_maps_t& info_map); + ~MemoryMapRegionSnapshotFuchsia() override; + + virtual const MINIDUMP_MEMORY_INFO& AsMinidumpMemoryInfo() const override; + + private: + MINIDUMP_MEMORY_INFO memory_info_; +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_FUCHSIA_MEMORY_MAP_REGION_SNAPSHOT_FUCHSIA_H_ diff --git a/snapshot/fuchsia/process_reader_fuchsia.h b/snapshot/fuchsia/process_reader_fuchsia.h index 36201af7..1392004e 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.h +++ b/snapshot/fuchsia/process_reader_fuchsia.h @@ -111,6 +111,9 @@ class ProcessReaderFuchsia { //! \brief Return a memory reader for the target process. const ProcessMemory* Memory() const { return process_memory_.get(); } + //! \brief Return a memory map for the target process. + const MemoryMapFuchsia* MemoryMap() const { return &memory_map_; } + private: //! Performs lazy initialization of the \a modules_ vector on behalf of //! Modules(). diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.cc b/snapshot/fuchsia/process_snapshot_fuchsia.cc index 12122f61..59e5d48a 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia.cc @@ -41,6 +41,13 @@ bool ProcessSnapshotFuchsia::Initialize(const zx::process& process) { InitializeThreads(); InitializeModules(); + for (const auto& entry : process_reader_.MemoryMap()->Entries()) { + if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) { + memory_map_.push_back( + std::make_unique<internal::MemoryMapRegionSnapshotFuchsia>(entry)); + } + } + INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -175,7 +182,11 @@ const ExceptionSnapshot* ProcessSnapshotFuchsia::Exception() const { std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotFuchsia::MemoryMap() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return std::vector<const MemoryMapRegionSnapshot*>(); + std::vector<const MemoryMapRegionSnapshot*> memory_map; + for (const auto& item : memory_map_) { + memory_map.push_back(item.get()); + } + return memory_map; } std::vector<HandleSnapshot> ProcessSnapshotFuchsia::Handles() const { diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.h b/snapshot/fuchsia/process_snapshot_fuchsia.h index 15c3bb7a..35538faa 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.h +++ b/snapshot/fuchsia/process_snapshot_fuchsia.h @@ -28,6 +28,7 @@ #include "snapshot/elf/elf_image_reader.h" #include "snapshot/elf/module_snapshot_elf.h" #include "snapshot/fuchsia/exception_snapshot_fuchsia.h" +#include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h" #include "snapshot/fuchsia/process_reader_fuchsia.h" #include "snapshot/fuchsia/system_snapshot_fuchsia.h" #include "snapshot/fuchsia/thread_snapshot_fuchsia.h" @@ -137,6 +138,8 @@ class ProcessSnapshotFuchsia : public ProcessSnapshot { ProcessReaderFuchsia process_reader_; ProcessMemoryRange memory_range_; std::map<std::string, std::string> annotations_simple_map_; + std::vector<std::unique_ptr<internal::MemoryMapRegionSnapshotFuchsia>> + memory_map_; UUID report_id_; UUID client_id_; timeval snapshot_time_; diff --git a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc new file mode 100644 index 00000000..0f3e3bdc --- /dev/null +++ b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc @@ -0,0 +1,141 @@ +// Copyright 2018 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/fuchsia/memory_map_region_snapshot_fuchsia.h" + +#include <dbghelp.h> +#include <zircon/syscalls.h> + +#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 "test/multiprocess_exec.h" +#include "util/fuchsia/scoped_task_suspend.h" + +namespace crashpad { +namespace test { +namespace { + +constexpr struct { + uint32_t zircon_perm; + size_t pages; + uint32_t minidump_perm; +} kTestMappingPermAndSizes[] = { + // Zircon doesn't currently allow write-only, execute-only, or + // write-execute-only, returning ZX_ERR_INVALID_ARGS on map. + {0, 5, PAGE_NOACCESS}, + {ZX_VM_PERM_READ, 6, PAGE_READONLY}, + // {ZX_VM_PERM_WRITE, 7, PAGE_WRITECOPY}, + // {ZX_VM_PERM_EXECUTE, 8, PAGE_EXECUTE}, + {ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 9, PAGE_READWRITE}, + {ZX_VM_PERM_READ | ZX_VM_PERM_EXECUTE, 10, PAGE_EXECUTE_READ}, + // {ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE, 11, PAGE_EXECUTE_WRITECOPY}, + {ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE, + 12, + PAGE_EXECUTE_READWRITE}, +}; + +CRASHPAD_CHILD_TEST_MAIN(AddressSpaceChildTestMain) { + // Create specifically sized mappings/permissions and write the address in + // our address space to the parent so that the reader can check they're read + // correctly. + for (const auto& t : kTestMappingPermAndSizes) { + zx_handle_t vmo = ZX_HANDLE_INVALID; + const size_t size = t.pages * PAGE_SIZE; + zx_status_t status = zx_vmo_create(size, 0, &vmo); + ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create"; + uintptr_t mapping_addr = 0; + status = zx_vmar_map( + zx_vmar_root_self(), t.zircon_perm, 0, vmo, 0, size, &mapping_addr); + ZX_CHECK(status == ZX_OK, status) << "zx_vmar_map"; + CheckedWriteFile(StdioFileHandle(StdioStream::kStandardOutput), + &mapping_addr, + sizeof(mapping_addr)); + } + + CheckedReadFileAtEOF(StdioFileHandle(StdioStream::kStandardInput)); + return 0; +} + +bool HasSingleMatchingMapping( + const std::vector<const MemoryMapRegionSnapshot*>& memory_map, + uintptr_t address, + size_t size, + uint32_t perm) { + const MemoryMapRegionSnapshot* matching = nullptr; + for (const auto* region : memory_map) { + const MINIDUMP_MEMORY_INFO& mmi = region->AsMinidumpMemoryInfo(); + if (mmi.BaseAddress == address) { + if (matching) { + LOG(ERROR) << "multiple mappings matching address"; + return false; + } + matching = region; + } + } + + if (!matching) + return false; + + const MINIDUMP_MEMORY_INFO& matching_mmi = matching->AsMinidumpMemoryInfo(); + return matching_mmi.Protect == perm && matching_mmi.RegionSize == size; +} + +class AddressSpaceTest : public MultiprocessExec { + public: + AddressSpaceTest() : MultiprocessExec() { + SetChildTestMainFunction("AddressSpaceChildTestMain"); + } + ~AddressSpaceTest() {} + + private: + void MultiprocessParent() override { + uintptr_t test_addresses[arraysize(kTestMappingPermAndSizes)]; + for (size_t i = 0; i < arraysize(test_addresses); ++i) { + ASSERT_TRUE(ReadFileExactly( + ReadPipeHandle(), &test_addresses[i], sizeof(test_addresses[i]))); + } + + ScopedTaskSuspend suspend(*ChildProcess()); + + ProcessSnapshotFuchsia process_snapshot; + ASSERT_TRUE(process_snapshot.Initialize(*ChildProcess())); + + for (size_t i = 0; i < arraysize(test_addresses); ++i) { + const auto& t = kTestMappingPermAndSizes[i]; + EXPECT_TRUE(HasSingleMatchingMapping(process_snapshot.MemoryMap(), + test_addresses[i], + t.pages * PAGE_SIZE, + t.minidump_perm)) + << base::StringPrintf( + "index %zu, zircon_perm 0x%x, minidump_perm 0x%x", + i, + t.zircon_perm, + t.minidump_perm); + } + } + + DISALLOW_COPY_AND_ASSIGN(AddressSpaceTest); +}; + +TEST(ProcessSnapshotFuchsiaTest, AddressSpaceMapping) { + AddressSpaceTest test; + test.Run(); +} + +} // namespace +} // namespace test +} // namespace crashpad From 2afe6dc210e3f52da56bc28d234f65d62b490ace Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 17 Dec 2018 14:27:46 -0800 Subject: [PATCH 093/401] android/linux: Support modules with shared relros on Android Add MemoryMap::Iterator to support different strategies for locating the start of module mappings on Android and Linux. Beginning with 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 containing the dynamic segment could have a name, device, and inode which are different than the other mappings for the module. The revised strategy for Android at API 21+ is to search all mappings in reverse order from they dynamic array mapping until a module is parsed with the expected dynamic array address. Linux and Android 20- continue to select mappings using the device, inode, and file offsets of the mappings. Bug: crashpad:268 Change-Id: I30e95e51cb6874c00875d2a9c57f1249877736d4 Reviewed-on: https://chromium-review.googlesource.com/c/1374375 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- compat/BUILD.gn | 2 + compat/android/android/api-level.cc | 50 +++++++++++++++ compat/android/android/api-level.h | 38 ++++++++++++ compat/compat.gyp | 2 + snapshot/elf/elf_image_reader_test.cc | 7 +-- snapshot/linux/debug_rendezvous_test.cc | 35 +++-------- snapshot/linux/process_reader_linux.cc | 44 ++++++++----- snapshot/linux/process_reader_linux_test.cc | 2 +- util/linux/memory_map.cc | 65 +++++++++++++++++-- util/linux/memory_map.h | 28 ++++++++- util/linux/memory_map_test.cc | 69 +++++++++++---------- 11 files changed, 256 insertions(+), 86 deletions(-) create mode 100644 compat/android/android/api-level.cc create mode 100644 compat/android/android/api-level.h diff --git a/compat/BUILD.gn b/compat/BUILD.gn index 2bfe074f..9f247a45 100644 --- a/compat/BUILD.gn +++ b/compat/BUILD.gn @@ -75,6 +75,8 @@ compat_target("compat") { if (crashpad_is_android) { sources += [ + "android/android/api-level.cc", + "android/android/api-level.h", "android/dlfcn_internal.cc", "android/dlfcn_internal.h", "android/elf.h", diff --git a/compat/android/android/api-level.cc b/compat/android/android/api-level.cc new file mode 100644 index 00000000..1a553368 --- /dev/null +++ b/compat/android/android/api-level.cc @@ -0,0 +1,50 @@ +// Copyright 2018 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 <android/api-level.h> + +#include <dlfcn.h> +#include <limits.h> +#include <stdlib.h> +#include <sys/system_properties.h> + +#include "dlfcn_internal.h" + +#if __ANDROID_API__ < 29 + +extern "C" { + +int android_get_device_api_level() { + using FuncType = int (*)(); + static const FuncType bionic_get_device_api_level = + reinterpret_cast<FuncType>( + crashpad::internal::Dlsym(RTLD_NEXT, "android_get_device_api_level")); + + if (bionic_get_device_api_level) { + return bionic_get_device_api_level(); + } + + char api_string[PROP_VALUE_MAX]; + int length = __system_property_get("ro.build.version.sdk", api_string); + if (length <= 0) { + return -1; + } + + int api_level = atoi(api_string); + return api_level > 0 ? api_level : -1; +} + +} // extern "C" + +#endif // __ANDROID_API__ < 29 diff --git a/compat/android/android/api-level.h b/compat/android/android/api-level.h new file mode 100644 index 00000000..03794cbd --- /dev/null +++ b/compat/android/android/api-level.h @@ -0,0 +1,38 @@ +// Copyright 2018 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_ANDROID_ANDROID_API_LEVEL_H_ +#define CRASHPAD_COMPAT_ANDROID_ANDROID_API_LEVEL_H_ + +#include_next <android/api-level.h> + +#include <sys/cdefs.h> + +#if __ANDROID_API__ < 29 + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns the API level of the device or -1 if it can't be determined. This +// function is provided by Bionic at API 29. +int android_get_device_api_level(); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __ANDROID_API__ < 29 + +#endif // CRASHPAD_COMPAT_ANDROID_ANDROID_API_LEVEL_H_ diff --git a/compat/compat.gyp b/compat/compat.gyp index 1229ee0c..6294d1fc 100644 --- a/compat/compat.gyp +++ b/compat/compat.gyp @@ -20,6 +20,8 @@ { 'target_name': 'crashpad_compat', 'sources': [ + 'android/android/api-level.cc', + 'android/android/api-level.h', 'android/dlfcn_internal.cc', 'android/dlfcn_internal.h', 'android/elf.h', diff --git a/snapshot/elf/elf_image_reader_test.cc b/snapshot/elf/elf_image_reader_test.cc index 2cc0faa5..0846ada4 100644 --- a/snapshot/elf/elf_image_reader_test.cc +++ b/snapshot/elf/elf_image_reader_test.cc @@ -100,10 +100,9 @@ void LocateExecutable(PtraceConnection* connection, ASSERT_TRUE(memory_map.Initialize(connection)); const MemoryMap::Mapping* phdr_mapping = memory_map.FindMapping(phdrs); ASSERT_TRUE(phdr_mapping); - std::vector<const MemoryMap::Mapping*> possible_mappings = - memory_map.FindFilePossibleMmapStarts(*phdr_mapping); - ASSERT_EQ(possible_mappings.size(), 1u); - *elf_address = possible_mappings[0]->range.Base(); + auto possible_mappings = memory_map.FindFilePossibleMmapStarts(*phdr_mapping); + ASSERT_EQ(possible_mappings->Count(), 1u); + *elf_address = possible_mappings->Next()->range.Base(); } #endif // OS_FUCHSIA diff --git a/snapshot/linux/debug_rendezvous_test.cc b/snapshot/linux/debug_rendezvous_test.cc index 431e2bbe..be22c903 100644 --- a/snapshot/linux/debug_rendezvous_test.cc +++ b/snapshot/linux/debug_rendezvous_test.cc @@ -37,28 +37,13 @@ #include "util/process/process_memory_range.h" #if defined(OS_ANDROID) -#include <sys/system_properties.h> +#include <android/api-level.h> #endif namespace crashpad { namespace test { namespace { -#if defined(OS_ANDROID) -int AndroidRuntimeAPI() { - char api_string[PROP_VALUE_MAX]; - int length = __system_property_get("ro.build.version.sdk", api_string); - if (length <= 0) { - return -1; - } - - int api_level; - bool success = - base::StringToInt(base::StringPiece(api_string, length), &api_level); - return success ? api_level : -1; -} -#endif // OS_ANDROID - 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 @@ -74,10 +59,10 @@ void TestAgainstTarget(PtraceConnection* connection) { const MemoryMap::Mapping* phdr_mapping = mappings.FindMapping(phdrs); ASSERT_TRUE(phdr_mapping); - std::vector<const MemoryMap::Mapping*> exe_mappings = - mappings.FindFilePossibleMmapStarts(*phdr_mapping); - ASSERT_EQ(exe_mappings.size(), 1u); - LinuxVMAddress elf_address = exe_mappings[0]->range.Base(); + + auto exe_mappings = mappings.FindFilePossibleMmapStarts(*phdr_mapping); + ASSERT_EQ(exe_mappings->Count(), 1u); + LinuxVMAddress elf_address = exe_mappings->Next()->range.Base(); ProcessMemoryLinux memory; ASSERT_TRUE(memory.Initialize(connection->GetProcessID())); @@ -94,7 +79,7 @@ void TestAgainstTarget(PtraceConnection* connection) { ASSERT_TRUE(debug.Initialize(range, debug_address)); #if defined(OS_ANDROID) - const int android_runtime_api = AndroidRuntimeAPI(); + const int android_runtime_api = android_get_device_api_level(); ASSERT_GE(android_runtime_api, 1); EXPECT_NE(debug.Executable()->name.find("crashpad_snapshot_test"), @@ -143,13 +128,13 @@ void TestAgainstTarget(PtraceConnection* connection) { mappings.FindMapping(module.dynamic_array); ASSERT_TRUE(dyn_mapping); - std::vector<const MemoryMap::Mapping*> possible_mappings = - mappings.FindFilePossibleMmapStarts(*dyn_mapping); - ASSERT_GE(possible_mappings.size(), 1u); + auto possible_mappings = mappings.FindFilePossibleMmapStarts(*dyn_mapping); + ASSERT_GE(possible_mappings->Count(), 1u); std::unique_ptr<ElfImageReader> module_reader; const MemoryMap::Mapping* module_mapping = nullptr; - for (const auto mapping : possible_mappings) { + const MemoryMap::Mapping* mapping = nullptr; + while ((mapping = possible_mappings->Next())) { auto parsed_module = std::make_unique<ElfImageReader>(); VMAddress dynamic_address; if (parsed_module->Initialize(range, mapping->range.Base()) && diff --git a/snapshot/linux/process_reader_linux.cc b/snapshot/linux/process_reader_linux.cc index 811ddd03..c1d6c40f 100644 --- a/snapshot/linux/process_reader_linux.cc +++ b/snapshot/linux/process_reader_linux.cc @@ -29,6 +29,10 @@ #include "util/linux/auxiliary_vector.h" #include "util/linux/proc_stat_reader.h" +#if defined(OS_ANDROID) +#include <android/api-level.h> +#endif + namespace crashpad { namespace { @@ -352,17 +356,15 @@ void ProcessReaderLinux::InitializeModules() { return; } - std::vector<const MemoryMap::Mapping*> possible_mappings = + auto possible_mappings = memory_map_.FindFilePossibleMmapStarts(*phdr_mapping); - for (auto riter = possible_mappings.rbegin(); - riter != possible_mappings.rend(); - ++riter) { - auto mapping = *riter; + const MemoryMap::Mapping* mapping = nullptr; + while ((mapping = possible_mappings->Next())) { auto parsed_exe = std::make_unique<ElfImageReader>(); if (parsed_exe->Initialize( range, mapping->range.Base(), - /* verbose= */ possible_mappings.size() == 1) && + /* verbose= */ possible_mappings->Count() == 1) && parsed_exe->GetProgramHeaderTableAddress() == phdrs) { exe_mapping = mapping; exe_reader = std::move(parsed_exe); @@ -370,7 +372,8 @@ void ProcessReaderLinux::InitializeModules() { } } if (!exe_mapping) { - LOG(ERROR) << "no exe mappings " << possible_mappings.size(); + LOG(ERROR) << "no exe mappings 0x" << std::hex + << phdr_mapping->range.Base(); return; } } @@ -407,18 +410,30 @@ void ProcessReaderLinux::InitializeModules() { continue; } - std::vector<const MemoryMap::Mapping*> possible_mappings = +#if defined(OS_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 + // to the attributes of the other mappings for the module. In this case, + // search all mappings in reverse order from dyn_mapping until a module is + // parsed whose dynamic address matches the value in the debug link. + static int api_level = android_get_device_api_level(); + auto possible_mappings = + (api_level >= 21 || api_level < 0) + ? memory_map_.ReverseIteratorFrom(*dyn_mapping) + : memory_map_.FindFilePossibleMmapStarts(*dyn_mapping); +#else + auto possible_mappings = memory_map_.FindFilePossibleMmapStarts(*dyn_mapping); - for (auto riter = possible_mappings.rbegin(); - riter != possible_mappings.rend(); - ++riter) { - auto mapping = *riter; +#endif + const MemoryMap::Mapping* mapping = nullptr; + while ((mapping = possible_mappings->Next())) { auto parsed_module = std::make_unique<ElfImageReader>(); VMAddress dynamic_address; if (parsed_module->Initialize( range, mapping->range.Base(), - /* verbose= */ possible_mappings.size() == 1) && + /* verbose= */ possible_mappings->Count() == 1) && parsed_module->GetDynamicArrayAddress(&dynamic_address) && dynamic_address == entry.dynamic_array) { module_mapping = mapping; @@ -427,7 +442,8 @@ void ProcessReaderLinux::InitializeModules() { } } if (!module_mapping) { - LOG(ERROR) << "no module mappings " << possible_mappings.size(); + LOG(ERROR) << "no module mappings 0x" << std::hex + << dyn_mapping->range.Base(); continue; } } diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index d827f35d..1edc5ab2 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -715,7 +715,7 @@ void ExpectTestModule(ProcessReaderLinux* reader, auto dynamic_mapping = reader->GetMemoryMap()->FindMapping(dynamic_addr); auto mappings = reader->GetMemoryMap()->FindFilePossibleMmapStarts(*dynamic_mapping); - EXPECT_EQ(mappings.size(), 2u); + EXPECT_EQ(mappings->Count(), 2u); return; } } diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index 495adf7c..0bcca3fa 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -204,6 +204,48 @@ ParseResult ParseMapsLine(DelimitedFileReader* maps_file_reader, return ParseResult::kSuccess; } +class SparseReverseIterator : public MemoryMap::Iterator { + public: + SparseReverseIterator(const std::vector<const MemoryMap::Mapping*>& mappings) + : mappings_(mappings), riter_(mappings_.rbegin()){}; + + SparseReverseIterator() : mappings_(), riter_(mappings_.rend()) {} + + // Iterator: + const MemoryMap::Mapping* Next() override { + return riter_ == mappings_.rend() ? nullptr : *(riter_++); + } + + unsigned int Count() override { return mappings_.rend() - riter_; } + + private: + std::vector<const MemoryMap::Mapping*> mappings_; + std::vector<const MemoryMap::Mapping*>::reverse_iterator riter_; + + DISALLOW_COPY_AND_ASSIGN(SparseReverseIterator); +}; + +class FullReverseIterator : public MemoryMap::Iterator { + public: + FullReverseIterator( + std::vector<MemoryMap::Mapping>::const_reverse_iterator rbegin, + std::vector<MemoryMap::Mapping>::const_reverse_iterator rend) + : riter_(rbegin), rend_(rend) {} + + // Iterator: + const MemoryMap::Mapping* Next() override { + return riter_ == rend_ ? nullptr : &*riter_++; + } + + unsigned int Count() override { return rend_ - riter_; } + + private: + std::vector<MemoryMap::Mapping>::const_reverse_iterator riter_; + std::vector<MemoryMap::Mapping>::const_reverse_iterator rend_; + + DISALLOW_COPY_AND_ASSIGN(FullReverseIterator); +}; + } // namespace MemoryMap::Mapping::Mapping() @@ -296,7 +338,7 @@ const MemoryMap::Mapping* MemoryMap::FindMappingWithName( return nullptr; } -std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts( +std::unique_ptr<MemoryMap::Iterator> MemoryMap::FindFilePossibleMmapStarts( const Mapping& mapping) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); @@ -308,12 +350,12 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts( for (const auto& candidate : mappings_) { if (mapping.Equals(candidate)) { possible_starts.push_back(&candidate); - return possible_starts; + return std::make_unique<SparseReverseIterator>(possible_starts); } } LOG(ERROR) << "mapping not found"; - return std::vector<const Mapping*>(); + return std::make_unique<SparseReverseIterator>(); } #if defined(OS_ANDROID) @@ -341,7 +383,7 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts( possible_starts.push_back(&candidate); } if (mapping.Equals(candidate)) { - return possible_starts; + return std::make_unique<SparseReverseIterator>(possible_starts); } } } @@ -359,12 +401,23 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts( possible_starts.push_back(&candidate); } if (mapping.Equals(candidate)) { - return possible_starts; + return std::make_unique<SparseReverseIterator>(possible_starts); } } LOG(ERROR) << "mapping not found"; - return std::vector<const Mapping*>(); + return std::make_unique<SparseReverseIterator>(); +} + +std::unique_ptr<MemoryMap::Iterator> MemoryMap::ReverseIteratorFrom( + const Mapping& target) const { + for (auto riter = mappings_.crbegin(); riter != mappings_.rend(); ++riter) { + if (riter->Equals(target)) { + return std::make_unique<FullReverseIterator>(riter, mappings_.rend()); + } + } + return std::make_unique<FullReverseIterator>(mappings_.rend(), + mappings_.rend()); } } // namespace crashpad diff --git a/util/linux/memory_map.h b/util/linux/memory_map.h index 28b8901f..a062b560 100644 --- a/util/linux/memory_map.h +++ b/util/linux/memory_map.h @@ -17,6 +17,7 @@ #include <sys/types.h> +#include <memory> #include <string> #include <vector> @@ -76,6 +77,24 @@ class MemoryMap { //! it was obtained from. const Mapping* FindMappingWithName(const std::string& name) const; + //! \brief An abstract base class for iterating over ordered sets of mappings + //! in a MemoryMap. + class Iterator { + public: + virtual ~Iterator() = default; + + //! \return the mapping pointed to by the iterator and advance the iterator + //! to the next mapping. If there are no more mappings, this method + //! returns `nullptr` on all subsequent invocations. + virtual const Mapping* Next() = 0; + + //! \return the number of mappings remaining. + virtual unsigned int Count() = 0; + + protected: + Iterator() = default; + }; + //! \brief Find possible initial mappings of files mapped over several //! segments. //! @@ -99,10 +118,15 @@ class MemoryMap { //! map a file, \a mapping is returned in \a possible_starts. //! //! \param[in] mapping A Mapping whose series to find the start of. - //! \return a vector of the possible mapping starts. - std::vector<const Mapping*> FindFilePossibleMmapStarts( + //! \return a reverse iterator over the possible mapping starts, starting from + //! the mapping with highest base address. + std::unique_ptr<Iterator> FindFilePossibleMmapStarts( const Mapping& mapping) const; + //! \return A reverse iterator over all mappings in the MemoryMap from \a + //! mapping to the start of the MemoryMap. + std::unique_ptr<Iterator> ReverseIteratorFrom(const Mapping& mapping) const; + private: std::vector<Mapping> mappings_; InitializationStateDcheck initialized_; diff --git a/util/linux/memory_map_test.cc b/util/linux/memory_map_test.cc index 77d832b6..2df44b3a 100644 --- a/util/linux/memory_map_test.cc +++ b/util/linux/memory_map_test.cc @@ -373,22 +373,20 @@ void ExpectFindFilePossibleMmapStarts(LinuxVMAddress mapping_start, ASSERT_NE(mapping1, mapping2); ASSERT_NE(mapping2, mapping3); - std::vector<const MemoryMap::Mapping*> mappings; - - mappings = map.FindFilePossibleMmapStarts(*mapping1); - ASSERT_EQ(mappings.size(), 1u); - EXPECT_EQ(mappings[0], mapping1); + auto mappings = map.FindFilePossibleMmapStarts(*mapping1); + ASSERT_EQ(mappings->Count(), 1u); + EXPECT_EQ(mappings->Next(), mapping1); mappings = map.FindFilePossibleMmapStarts(*mapping2); - ASSERT_EQ(mappings.size(), 1u); - EXPECT_EQ(mappings[0], mapping2); + ASSERT_EQ(mappings->Count(), 1u); + EXPECT_EQ(mappings->Next(), mapping2); mappings = map.FindFilePossibleMmapStarts(*mapping3); #if defined(OS_ANDROID) - EXPECT_EQ(mappings.size(), 2u); + EXPECT_EQ(mappings->Count(), 2u); #else - ASSERT_EQ(mappings.size(), 1u); - EXPECT_EQ(mappings[0], mapping1); + ASSERT_EQ(mappings->Count(), 1u); + EXPECT_EQ(mappings->Next(), mapping1); #endif } @@ -432,29 +430,30 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) { ASSERT_NE(mapping1, mapping2); ASSERT_NE(mapping2, mapping3); - std::vector<const MemoryMap::Mapping*> mappings; - #if defined(OS_ANDROID) - mappings = map.FindFilePossibleMmapStarts(*mapping1); - EXPECT_EQ(mappings.size(), 1u); + auto mappings = map.FindFilePossibleMmapStarts(*mapping1); + EXPECT_EQ(mappings->Count(), 1u); + EXPECT_EQ(mappings->Next(), mapping1); + EXPECT_EQ(mappings->Next(), nullptr); mappings = map.FindFilePossibleMmapStarts(*mapping2); - EXPECT_EQ(mappings.size(), 2u); + EXPECT_EQ(mappings->Count(), 2u); mappings = map.FindFilePossibleMmapStarts(*mapping3); - EXPECT_EQ(mappings.size(), 3u); + EXPECT_EQ(mappings->Count(), 3u); #else - mappings = map.FindFilePossibleMmapStarts(*mapping1); - ASSERT_EQ(mappings.size(), 1u); - EXPECT_EQ(mappings[0], mapping1); + auto mappings = map.FindFilePossibleMmapStarts(*mapping1); + ASSERT_EQ(mappings->Count(), 1u); + EXPECT_EQ(mappings->Next(), mapping1); + EXPECT_EQ(mappings->Next(), nullptr); mappings = map.FindFilePossibleMmapStarts(*mapping2); - ASSERT_EQ(mappings.size(), 1u); - EXPECT_EQ(mappings[0], mapping1); + ASSERT_EQ(mappings->Count(), 1u); + EXPECT_EQ(mappings->Next(), mapping1); mappings = map.FindFilePossibleMmapStarts(*mapping3); - ASSERT_EQ(mappings.size(), 1u); - EXPECT_EQ(mappings[0], mapping1); + ASSERT_EQ(mappings->Count(), 1u); + EXPECT_EQ(mappings->Next(), mapping1); #endif #if defined(ARCH_CPU_64_BITS) @@ -464,7 +463,9 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) { #endif MemoryMap::Mapping bad_mapping; bad_mapping.range.SetRange(is_64_bit, 0, 1); - EXPECT_EQ(map.FindFilePossibleMmapStarts(bad_mapping).size(), 0u); + mappings = map.FindFilePossibleMmapStarts(bad_mapping); + EXPECT_EQ(mappings->Count(), 0u); + EXPECT_EQ(mappings->Next(), nullptr); } // Make the second page an anonymous mapping @@ -578,45 +579,45 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) { ASSERT_TRUE(mapping); auto possible_starts = map.FindFilePossibleMmapStarts(*mapping); #if defined(OS_ANDROID) - EXPECT_EQ(possible_starts.size(), 1u); + EXPECT_EQ(possible_starts->Count(), 1u); #else - EXPECT_EQ(possible_starts.size(), 0u); + EXPECT_EQ(possible_starts->Count(), 0u); #endif mapping = map.FindMapping(file_mapping1.addr_as<VMAddress>()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); #if defined(OS_ANDROID) - EXPECT_EQ(possible_starts.size(), 2u); + EXPECT_EQ(possible_starts->Count(), 2u); #else - EXPECT_EQ(possible_starts.size(), 1u); + EXPECT_EQ(possible_starts->Count(), 1u); #endif mapping = map.FindMapping(file_mapping2.addr_as<VMAddress>()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); #if defined(OS_ANDROID) - EXPECT_EQ(possible_starts.size(), 3u); + EXPECT_EQ(possible_starts->Count(), 3u); #else - EXPECT_EQ(possible_starts.size(), 2u); + EXPECT_EQ(possible_starts->Count(), 2u); #endif mapping = map.FindMapping(file_mapping3.addr_as<VMAddress>()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); #if defined(OS_ANDROID) - EXPECT_EQ(possible_starts.size(), 4u); + EXPECT_EQ(possible_starts->Count(), 4u); #else - EXPECT_EQ(possible_starts.size(), 3u); + EXPECT_EQ(possible_starts->Count(), 3u); #endif mapping = map.FindMapping(file_mapping4.addr_as<VMAddress>()); ASSERT_TRUE(mapping); possible_starts = map.FindFilePossibleMmapStarts(*mapping); #if defined(OS_ANDROID) - EXPECT_EQ(possible_starts.size(), 5u); + EXPECT_EQ(possible_starts->Count(), 5u); #else - EXPECT_EQ(possible_starts.size(), 4u); + EXPECT_EQ(possible_starts->Count(), 4u); #endif } From 83867d52343b9657ad1263c2a6d5571dbc350b0c Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 18 Dec 2018 09:17:52 -0800 Subject: [PATCH 094/401] linux: Add ScopedPrSetDumpable Bug: 914246 Change-Id: I529467e92a5cbc2a372f4c12234cfd3af8ddfe0a Reviewed-on: https://chromium-review.googlesource.com/c/1382598 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_linux.cc | 2 ++ util/BUILD.gn | 2 ++ util/linux/scoped_pr_set_dumpable.cc | 41 ++++++++++++++++++++++++++ util/linux/scoped_pr_set_dumpable.h | 44 ++++++++++++++++++++++++++++ util/util.gyp | 2 ++ 5 files changed, 91 insertions(+) create mode 100644 util/linux/scoped_pr_set_dumpable.cc create mode 100644 util/linux/scoped_pr_set_dumpable.h diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 77faa0aa..ed1d7dfd 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -28,6 +28,7 @@ #include "util/file/file_io.h" #include "util/linux/exception_handler_client.h" #include "util/linux/exception_information.h" +#include "util/linux/scoped_pr_set_dumpable.h" #include "util/linux/scoped_pr_set_ptracer.h" #include "util/misc/from_pointer_cast.h" #include "util/posix/double_fork_and_exec.h" @@ -119,6 +120,7 @@ class LaunchAtCrashHandler { exception_information_.thread_id = syscall(SYS_gettid); ScopedPrSetPtracer set_ptracer(getpid(), /* may_log= */ false); + ScopedPrSetDumpable set_dumpable(/* may_log= */ false); pid_t pid = fork(); if (pid < 0) { diff --git a/util/BUILD.gn b/util/BUILD.gn index 9f47a41b..c02ecd4e 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -296,6 +296,8 @@ static_library("util") { "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", diff --git a/util/linux/scoped_pr_set_dumpable.cc b/util/linux/scoped_pr_set_dumpable.cc new file mode 100644 index 00000000..cbec009b --- /dev/null +++ b/util/linux/scoped_pr_set_dumpable.cc @@ -0,0 +1,41 @@ +// Copyright 2018 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/linux/scoped_pr_set_dumpable.h" + +#include <sys/prctl.h> + +#include "base/logging.h" + +namespace crashpad { + +ScopedPrSetDumpable::ScopedPrSetDumpable(bool may_log) : may_log_(may_log) { + int result = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0); + PLOG_IF(ERROR, result < 0 && may_log_) << "prctl"; + was_dumpable_ = result > 0; + + if (!was_dumpable_) { + result = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); + PLOG_IF(ERROR, result != 0 && may_log_) << "prctl"; + } +} + +ScopedPrSetDumpable::~ScopedPrSetDumpable() { + if (!was_dumpable_) { + int result = prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); + PLOG_IF(ERROR, result != 0 && may_log_) << "prctl"; + } +} + +} // namespace crashpad diff --git a/util/linux/scoped_pr_set_dumpable.h b/util/linux/scoped_pr_set_dumpable.h new file mode 100644 index 00000000..16819309 --- /dev/null +++ b/util/linux/scoped_pr_set_dumpable.h @@ -0,0 +1,44 @@ +// Copyright 2018 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_LINUX_SCOPED_PR_SET_DUMPABLE_H_ +#define CRASHPAD_UTIL_LINUX_SCOPED_PR_SET_DUMPABLE_H_ + +#include "base/macros.h" + +namespace crashpad { + +class ScopedPrSetDumpable { + public: + //! \brief Uses `PR_SET_DUMPABLE` to make the current process dumpable. + //! + //! Restores the dumpable flag to its original value on destruction. If the + //! original value couldn't be determined, the destructor attempts to restore + //! the flag to 0 (non-dumpable). + //! + //! \param[in] may_log `true` if this object may log error messages. + explicit ScopedPrSetDumpable(bool may_log); + + ~ScopedPrSetDumpable(); + + private: + bool was_dumpable_; + bool may_log_; + + DISALLOW_COPY_AND_ASSIGN(ScopedPrSetDumpable); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_LINUX_SCOPED_PR_SET_DUMPABLE_H_ diff --git a/util/util.gyp b/util/util.gyp index a8ed59e6..60e91304 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -74,6 +74,8 @@ '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', From f2a07982ff52d2fede88ef1a26c3e0ef72dbcc54 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 19 Dec 2018 12:41:20 -0800 Subject: [PATCH 095/401] Change edge case handling in ReadCStringInternal Currently, TaskMemory::ReadCStringInternal() treats the ReadCStringSizeLimited(size=0) case by returning an empty string; however, that is inconsistent with the documentation for that function and the equivalent implementation in ProcessMemory. The comment for the size parameter is: "The maximum number of bytes to read. The string is required to be `NUL`-terminated within this many bytes." My interpretation is that the ProcessMemory behavior is correct in failing on size=0 as a NUL can never be read. ReadCStringSizeLimited() is only used with a possibly null size in MachOImageReader::ReadDylinkerCommand(). In that case we read the dylinker_command string, which appears to also be verified to be a non-zero length null terminated string in load_dylinker() in bsd/kern/mach_loader.c so we shouldn't hit this case in the wild. Bug: crashpad:263 Change-Id: I2bd9c0ce3055154a98afdd19af95bb48d05f05a3 Reviewed-on: https://chromium-review.googlesource.com/c/1384448 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- util/mach/task_memory.cc | 7 +------ util/mach/task_memory_test.cc | 11 ++++------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/util/mach/task_memory.cc b/util/mach/task_memory.cc index 6168434d..ad4c8c39 100644 --- a/util/mach/task_memory.cc +++ b/util/mach/task_memory.cc @@ -117,12 +117,7 @@ bool TaskMemory::ReadCStringInternal(mach_vm_address_t address, bool has_size, mach_vm_size_t size, std::string* string) { - if (has_size) { - if (size == 0) { - string->clear(); - return true; - } - } else { + if (!has_size) { size = PAGE_SIZE; } diff --git a/util/mach/task_memory_test.cc b/util/mach/task_memory_test.cc index d9f0cb77..e3ef7601 100644 --- a/util/mach/task_memory_test.cc +++ b/util/mach/task_memory_test.cc @@ -314,9 +314,8 @@ TEST(TaskMemory, ReadCStringSizeLimited_ConstCharEmpty) { EXPECT_EQ(result, kConstCharEmpty); result.clear(); - ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory, kConstCharEmpty, 0, &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kConstCharEmpty); + EXPECT_FALSE( + ReadCStringSizeLimitedSelf(&memory, kConstCharEmpty, 0, &result)); } TEST(TaskMemory, ReadCStringSizeLimited_ConstCharShort) { @@ -335,7 +334,7 @@ TEST(TaskMemory, ReadCStringSizeLimited_ConstCharShort) { EXPECT_FALSE(result.empty()); EXPECT_EQ(result, kConstCharShort); - ASSERT_FALSE(ReadCStringSizeLimitedSelf( + EXPECT_FALSE(ReadCStringSizeLimitedSelf( &memory, kConstCharShort, arraysize(kConstCharShort) - 1, &result)); } @@ -360,10 +359,8 @@ TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharEmpty) { EXPECT_EQ(result, kStaticConstCharEmpty); result.clear(); - ASSERT_TRUE( + ASSERT_FALSE( ReadCStringSizeLimitedSelf(&memory, kStaticConstCharEmpty, 0, &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kStaticConstCharEmpty); } TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharShort) { From ffd666e16c5f67c7ea45813a233f25cfd3a9d81c Mon Sep 17 00:00:00 2001 From: Nathan Rogers <nathanrogers@google.com> Date: Mon, 17 Dec 2018 22:33:08 -0800 Subject: [PATCH 096/401] fuchsia: Update Paths::Executable documentation Update the "...namespaces.md..." link to its current URL. Change-Id: Ic30c6be5dba4f531e5b8a55af37555626398df5a Reviewed-on: https://chromium-review.googlesource.com/c/1381777 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/misc/paths_fuchsia.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/misc/paths_fuchsia.cc b/util/misc/paths_fuchsia.cc index 09084483..6dea6337 100644 --- a/util/misc/paths_fuchsia.cc +++ b/util/misc/paths_fuchsia.cc @@ -25,7 +25,7 @@ namespace crashpad { // static bool Paths::Executable(base::FilePath* path) { // Assume the environment has been set up following - // https://fuchsia.googlesource.com/docs/+/master/namespaces.md#typical-directory-structure + // https://fuchsia.googlesource.com/docs/+/master/the-book/namespaces.md#typical-directory-structure // . *path = base::FilePath("/pkg/bin/app"); return true; From bf6d2e028376ce48b14441ef26a6cff34888e926 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 19 Dec 2018 13:49:55 -0800 Subject: [PATCH 097/401] Refactor TaskMemory initialization Currently, TaskMemory implements the ProcessMemory interface almost exactly; however, it's initialized using a constructor instead of an Initialize method which makes it incompatible with a number of ProcessMemory tests. Change its initialization to match the other ProcessMemory classes. Bug: crashpad:263 Change-Id: I8022dc3e1827a5bb398aace0058ce9494b6b6eb6 Reviewed-on: https://chromium-review.googlesource.com/c/1384447 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/mac/process_reader_mac.cc | 8 ++++--- snapshot/mac/process_reader_mac.h | 4 ++-- util/mach/task_memory.cc | 18 ++++++++++++++- util/mach/task_memory.h | 19 ++++++++++++---- util/mach/task_memory_test.cc | 36 ++++++++++++++++++++---------- 5 files changed, 63 insertions(+), 22 deletions(-) diff --git a/snapshot/mac/process_reader_mac.cc b/snapshot/mac/process_reader_mac.cc index e142fd2e..4850bbab 100644 --- a/snapshot/mac/process_reader_mac.cc +++ b/snapshot/mac/process_reader_mac.cc @@ -113,9 +113,11 @@ bool ProcessReaderMac::Initialize(task_t task) { return false; } - is_64_bit_ = process_info_.Is64Bit(); + if (!task_memory_.Initialize(task)) { + return false; + } - task_memory_.reset(new TaskMemory(task)); + is_64_bit_ = process_info_.Is64Bit(); task_ = task; INITIALIZATION_STATE_SET_VALID(initialized_); @@ -441,7 +443,7 @@ void ProcessReaderMac::InitializeModules() { Module module; module.timestamp = image_info.imageFileModDate; - if (!task_memory_->ReadCString(image_info.imageFilePath, &module.name)) { + if (!task_memory_.ReadCString(image_info.imageFilePath, &module.name)) { LOG(WARNING) << "could not read dyld_image_info::imageFilePath"; // Proceed anyway with an empty module name. } diff --git a/snapshot/mac/process_reader_mac.h b/snapshot/mac/process_reader_mac.h index 91836dbb..8a5b2c80 100644 --- a/snapshot/mac/process_reader_mac.h +++ b/snapshot/mac/process_reader_mac.h @@ -138,7 +138,7 @@ class ProcessReaderMac { bool CPUTimes(timeval* user_time, timeval* system_time) const; //! \return Accesses the memory of the target task. - TaskMemory* Memory() { return task_memory_.get(); } + TaskMemory* Memory() { return &task_memory_; } //! \return The threads that are in the task (process). The first element (at //! index `0`) corresponds to the main thread. @@ -232,7 +232,7 @@ class ProcessReaderMac { std::vector<Thread> threads_; // owns send rights std::vector<Module> modules_; std::vector<std::unique_ptr<MachOImageReader>> module_readers_; - std::unique_ptr<TaskMemory> task_memory_; + TaskMemory task_memory_; task_t task_; // weak InitializationStateDcheck initialized_; diff --git a/util/mach/task_memory.cc b/util/mach/task_memory.cc index ad4c8c39..14069ddf 100644 --- a/util/mach/task_memory.cc +++ b/util/mach/task_memory.cc @@ -64,10 +64,18 @@ TaskMemory::MappedMemory::MappedMemory(vm_address_t vm_address, DCHECK_LE(user_end, vm_end); } -TaskMemory::TaskMemory(task_t task) : task_(task) { +TaskMemory::TaskMemory() : task_(TASK_NULL), initialized_() {} + +bool TaskMemory::Initialize(task_t task) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + task_ = task; + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; } bool TaskMemory::Read(mach_vm_address_t address, size_t size, void* buffer) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + std::unique_ptr<MappedMemory> memory = ReadMapped(address, size); if (!memory) { return false; @@ -80,6 +88,8 @@ bool TaskMemory::Read(mach_vm_address_t address, size_t size, void* buffer) { std::unique_ptr<TaskMemory::MappedMemory> TaskMemory::ReadMapped( mach_vm_address_t address, size_t size) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (size == 0) { return std::unique_ptr<MappedMemory>(new MappedMemory(0, 0, 0, 0)); } @@ -104,12 +114,16 @@ std::unique_ptr<TaskMemory::MappedMemory> TaskMemory::ReadMapped( } bool TaskMemory::ReadCString(mach_vm_address_t address, std::string* string) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return ReadCStringInternal(address, false, 0, string); } bool TaskMemory::ReadCStringSizeLimited(mach_vm_address_t address, mach_vm_size_t size, std::string* string) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return ReadCStringInternal(address, true, size, string); } @@ -117,6 +131,8 @@ bool TaskMemory::ReadCStringInternal(mach_vm_address_t address, bool has_size, mach_vm_size_t size, std::string* string) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (!has_size) { size = PAGE_SIZE; } diff --git a/util/mach/task_memory.h b/util/mach/task_memory.h index c8caf85c..118ff0ba 100644 --- a/util/mach/task_memory.h +++ b/util/mach/task_memory.h @@ -23,6 +23,7 @@ #include "base/mac/scoped_mach_vm.h" #include "base/macros.h" +#include "util/misc/initialization_state_dcheck.h" namespace crashpad { @@ -87,12 +88,21 @@ class TaskMemory { DISALLOW_COPY_AND_ASSIGN(MappedMemory); }; - //! \param[in] task A send right to the target task’s task port. This object - //! does not take ownership of the send right. - explicit TaskMemory(task_t task); - + TaskMemory(); ~TaskMemory() {} + //! \brief Initializes this object to read the memory of a task with the + //! provided task port. + //! + //! This method must be called successfully prior to calling any other method + //! in this class. + //! + //! \param[in] task A send right to the target task's task port. This object + //! does not take ownership of the send right. + //! + //! \return `true` on success, `false` on failure with a message logged. + bool Initialize(task_t task); + //! \brief Copies memory from the target task into a caller-provided buffer in //! the current task. //! @@ -170,6 +180,7 @@ class TaskMemory { std::string* string); task_t task_; // weak + InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(TaskMemory); }; diff --git a/util/mach/task_memory_test.cc b/util/mach/task_memory_test.cc index e3ef7601..904dfca7 100644 --- a/util/mach/task_memory_test.cc +++ b/util/mach/task_memory_test.cc @@ -44,7 +44,8 @@ TEST(TaskMemory, ReadSelf) { region[index] = (index % 256) ^ ((index >> 8) % 256); } - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); // This tests using both the Read() and ReadMapped() interfaces. std::string result(kSize, '\0'); @@ -119,7 +120,8 @@ TEST(TaskMemory, ReadSelfUnmapped) { mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE); ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_protect"); - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result(kSize, '\0'); EXPECT_FALSE(memory.Read(address, kSize, &result[0])); @@ -171,7 +173,8 @@ bool ReadCStringSelf(TaskMemory* memory, } TEST(TaskMemory, ReadCStringSelf) { - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result; const char kConstCharEmpty[] = ""; @@ -253,7 +256,8 @@ TEST(TaskMemory, ReadCStringSelfUnmapped) { mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE); ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_protect"); - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result; EXPECT_FALSE(memory.ReadCString(address, &result)); @@ -298,7 +302,8 @@ bool ReadCStringSizeLimitedSelf(TaskMemory* memory, } TEST(TaskMemory, ReadCStringSizeLimited_ConstCharEmpty) { - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result; static constexpr char kConstCharEmpty[] = ""; @@ -319,7 +324,8 @@ TEST(TaskMemory, ReadCStringSizeLimited_ConstCharEmpty) { } TEST(TaskMemory, ReadCStringSizeLimited_ConstCharShort) { - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result; static constexpr char kConstCharShort[] = "A short const char[]"; @@ -339,7 +345,8 @@ TEST(TaskMemory, ReadCStringSizeLimited_ConstCharShort) { } TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharEmpty) { - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result; static constexpr char kStaticConstCharEmpty[] = ""; @@ -364,7 +371,8 @@ TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharEmpty) { } TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharShort) { - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result; static constexpr char kStaticConstCharShort[] = @@ -391,7 +399,8 @@ TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharShort) { } TEST(TaskMemory, ReadCStringSizeLimited_StringShort) { - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result; std::string string_short("A short std::string in a function"); @@ -411,7 +420,8 @@ TEST(TaskMemory, ReadCStringSizeLimited_StringShort) { } TEST(TaskMemory, ReadCStringSizeLimited_StringLong) { - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result; std::string string_long; @@ -477,7 +487,8 @@ TEST(TaskMemory, MappedMemoryDeallocates) { // hopefully there are either no other threads or they’re all quiescent, so // nothing else should wind up mapped in the address. - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::unique_ptr<TaskMemory::MappedMemory> mapped; static constexpr char kTestBuffer[] = "hello!"; @@ -514,7 +525,8 @@ TEST(TaskMemory, MappedMemoryDeallocates) { TEST(TaskMemory, MappedMemoryReadCString) { // This tests the behavior of TaskMemory::MappedMemory::ReadCString(). - TaskMemory memory(mach_task_self()); + TaskMemory memory; + ASSERT_TRUE(memory.Initialize(mach_task_self())); std::unique_ptr<TaskMemory::MappedMemory> mapped; static constexpr char kTestBuffer[] = "0\0" "2\0" "45\0" "789"; From 7018a80b36beac71761f6187813bde71fc4e941b Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 20 Dec 2018 09:03:05 -0800 Subject: [PATCH 098/401] Simplify test set-up Use platform independent helpers to simplify initializing a ProcessMemory object in this test. Bug: crashpad:263 Change-Id: Id0f9e006f6dbaca31453803b8c790a6832e855e5 Reviewed-on: https://chromium-review.googlesource.com/c/1387264 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- util/process/process_memory_range_test.cc | 26 ++++------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/util/process/process_memory_range_test.cc b/util/process/process_memory_range_test.cc index 19de2b10..fa2a893b 100644 --- a/util/process/process_memory_range_test.cc +++ b/util/process/process_memory_range_test.cc @@ -20,18 +20,8 @@ #include "build/build_config.h" #include "gtest/gtest.h" #include "util/misc/from_pointer_cast.h" - -#if defined(OS_FUCHSIA) -#include <lib/zx/process.h> - -#include "util/process/process_memory_fuchsia.h" -#elif defined(OS_WIN) -#include "util/process/process_memory_win.h" -#else -#include <unistd.h> - -#include "util/process/process_memory_linux.h" -#endif +#include "util/process/process_memory_native.h" +#include "test/process_type.h" namespace crashpad { namespace test { @@ -49,16 +39,8 @@ TEST(ProcessMemoryRange, Basic) { constexpr bool is_64_bit = false; #endif // ARCH_CPU_64_BITS -#if defined(OS_FUCHSIA) - ProcessMemoryFuchsia memory; - ASSERT_TRUE(memory.Initialize(*zx::process::self())); -#elif defined(OS_WIN) - ProcessMemoryWin memory; - ASSERT_TRUE(memory.Initialize(GetCurrentProcess())); -#elif defined(OS_LINUX) || defined(OS_ANDROID) - ProcessMemoryLinux memory; - ASSERT_TRUE(memory.Initialize(getpid())); -#endif // OS_FUCHSIA + ProcessMemoryNative memory; + ASSERT_TRUE(memory.Initialize(GetSelfProcess())); ProcessMemoryRange range; ASSERT_TRUE(range.Initialize(&memory, is_64_bit)); From 8b2ec2aae4b2721079c3a28a4cde1d13d2cca999 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 20 Dec 2018 11:12:51 -0800 Subject: [PATCH 099/401] Make TaskMemory a child class of ProcessMemory Currently TaskMemory re-implements a number of Read* routines that are implemented in a platform-independent way in ProcessMemory with access to a single platform-specific ReadUpTo method. Implement the ReadUpTo method for TaskMemory and subclass it from ProcessMemory to inherit the remaining methods. The ProcessMemoryTests didn't work on macOS because MultiprocessExec can not access the child process' task port without root privileges or the task_for_pid entitlement. Create an adaptor class for those tests to use MachMultiprocess so that the child process sends its task port to the parent. Bug: crashpad:263 Change-Id: Id8e1788a74fe957f05703a5eb569ca3bf9870369 Reviewed-on: https://chromium-review.googlesource.com/c/1387265 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- test/multiprocess_exec.h | 4 +- test/multiprocess_exec_posix.cc | 8 ++ test/process_type.cc | 6 +- test/process_type.h | 8 +- util/BUILD.gn | 29 ++----- util/mach/task_memory.cc | 77 +++++-------------- util/mach/task_memory.h | 65 ++-------------- util/process/process_memory_native.h | 4 + util/process/process_memory_test.cc | 108 +++++++++++++++++++++------ 9 files changed, 141 insertions(+), 168 deletions(-) diff --git a/test/multiprocess_exec.h b/test/multiprocess_exec.h index 84335b28..1168f800 100644 --- a/test/multiprocess_exec.h +++ b/test/multiprocess_exec.h @@ -122,7 +122,9 @@ class MultiprocessExec : public Multiprocess { //! //! This method is only valid during the body of MultiprocessParent(). //! - //! \return A platform-specific type representing the child process. + //! \return A platform-specific type representing the child process. This + //! method can fail on macOS because access to a child's task port + //! requires the task_for_pid entitlement. ProcessType ChildProcess(); protected: diff --git a/test/multiprocess_exec_posix.cc b/test/multiprocess_exec_posix.cc index c91b7f73..bf4263a2 100644 --- a/test/multiprocess_exec_posix.cc +++ b/test/multiprocess_exec_posix.cc @@ -29,6 +29,10 @@ #include <stdio_ext.h> #endif +#if defined(OS_MACOSX) +#include "util/mach/task_for_pid.h" +#endif + namespace crashpad { namespace test { @@ -149,7 +153,11 @@ void MultiprocessExec::MultiprocessChild() { } ProcessType MultiprocessExec::ChildProcess() { +#if defined(OS_MACOSX) + return TaskForPID(ChildPID()); +#else return ChildPID(); +#endif } } // namespace test diff --git a/test/process_type.cc b/test/process_type.cc index 9fd08dd9..94fd912d 100644 --- a/test/process_type.cc +++ b/test/process_type.cc @@ -16,7 +16,7 @@ #if defined(OS_FUCHSIA) #include <lib/zx/process.h> -#elif defined(OS_POSIX) +#elif defined(OS_LINUX) || defined(OS_ANDROID) #include <unistd.h> #endif @@ -26,10 +26,12 @@ namespace test { ProcessType GetSelfProcess() { #if defined(OS_FUCHSIA) return zx::process::self(); -#elif defined(OS_POSIX) +#elif defined(OS_LINUX) || defined(OS_ANDROID) return getpid(); #elif defined(OS_WIN) return GetCurrentProcess(); +#elif defined(OS_MACOSX) + return mach_task_self(); #endif } diff --git a/test/process_type.h b/test/process_type.h index 240c083d..dc99687a 100644 --- a/test/process_type.h +++ b/test/process_type.h @@ -19,10 +19,12 @@ #if defined(OS_FUCHSIA) #include <lib/zx/process.h> -#elif defined(OS_POSIX) +#elif defined(OS_LINUX) || defined(OS_ANDROID) #include <sys/types.h> #elif defined(OS_WIN) #include <windows.h> +#elif defined(OS_MACOSX) +#include <mach/mach.h> #endif namespace crashpad { @@ -30,11 +32,13 @@ namespace test { #if defined(OS_FUCHSIA) using ProcessType = zx::unowned_process; -#elif defined(OS_POSIX) || DOXYGEN +#elif defined(OS_LINUX) || defined(OS_ANDROID) || DOXYGEN //! \brief Alias for platform-specific type to represent a process. using ProcessType = pid_t; #elif defined(OS_WIN) using ProcessType = HANDLE; +#elif defined(OS_MACOSX) +using ProcessType = task_t; #else #error Port. #endif diff --git a/util/BUILD.gn b/util/BUILD.gn index c02ecd4e..e43c42f0 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -137,6 +137,11 @@ static_library("util") { "numeric/in_range_cast.h", "numeric/int128.h", "numeric/safe_assignment.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", @@ -313,19 +318,6 @@ static_library("util") { ] } - if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia || - crashpad_is_win) { - sources += [ - "process/process_memory.cc", - "process/process_memory.h", - "process/process_memory_native.h", - - # TODO: Port to all platforms. - "process/process_memory_range.cc", - "process/process_memory_range.h", - ] - } - if (crashpad_is_win) { sources += [ "file/directory_reader_win.cc", @@ -562,6 +554,8 @@ source_set("util_test") { "numeric/checked_range_test.cc", "numeric/in_range_cast_test.cc", "numeric/int128_test.cc", + "process/process_memory_range_test.cc", + "process/process_memory_test.cc", "stdlib/aligned_allocator_test.cc", "stdlib/map_insert_test.cc", "stdlib/string_number_conversion_test.cc", @@ -633,15 +627,6 @@ source_set("util_test") { sources += [ "misc/capture_context_test_util_fuchsia.cc" ] } - if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia || - crashpad_is_win) { - sources += [ - # TODO: Port to all platforms. - "process/process_memory_range_test.cc", - "process/process_memory_test.cc", - ] - } - if (crashpad_is_win) { sources += [ "misc/capture_context_test_util_win.cc", diff --git a/util/mach/task_memory.cc b/util/mach/task_memory.cc index 14069ddf..eb8b1f57 100644 --- a/util/mach/task_memory.cc +++ b/util/mach/task_memory.cc @@ -73,21 +73,9 @@ bool TaskMemory::Initialize(task_t task) { return true; } -bool TaskMemory::Read(mach_vm_address_t address, size_t size, void* buffer) { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); - - std::unique_ptr<MappedMemory> memory = ReadMapped(address, size); - if (!memory) { - return false; - } - - memcpy(buffer, memory->data(), size); - return true; -} - std::unique_ptr<TaskMemory::MappedMemory> TaskMemory::ReadMapped( mach_vm_address_t address, - size_t size) { + size_t size) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); if (size == 0) { @@ -113,58 +101,29 @@ std::unique_ptr<TaskMemory::MappedMemory> TaskMemory::ReadMapped( new MappedMemory(region, region_size, address - region_address, size)); } -bool TaskMemory::ReadCString(mach_vm_address_t address, std::string* string) { +ssize_t TaskMemory::ReadUpTo(VMAddress address, + size_t size, + void* buffer) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); + DCHECK_LE(size, (size_t)std::numeric_limits<ssize_t>::max()); - return ReadCStringInternal(address, false, 0, string); -} + std::unique_ptr<MappedMemory> memory = ReadMapped(address, size); + if (!memory) { + // If we can not read the entire mapping, try to perform a short read of the + // first page instead. This is necessary to support ReadCString(). + size_t short_read = PAGE_SIZE - (address % PAGE_SIZE); + if (short_read >= size) + return -1; -bool TaskMemory::ReadCStringSizeLimited(mach_vm_address_t address, - mach_vm_size_t size, - std::string* string) { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); + memory = ReadMapped(address, short_read); + if (!memory) + return -1; - return ReadCStringInternal(address, true, size, string); -} - -bool TaskMemory::ReadCStringInternal(mach_vm_address_t address, - bool has_size, - mach_vm_size_t size, - std::string* string) { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); - - if (!has_size) { - size = PAGE_SIZE; + size = short_read; } - std::string local_string; - mach_vm_address_t read_address = address; - do { - mach_vm_size_t read_length = - std::min(size, PAGE_SIZE - (read_address % PAGE_SIZE)); - std::unique_ptr<MappedMemory> read_region = - ReadMapped(read_address, read_length); - if (!read_region) { - return false; - } - - const char* read_region_data = - reinterpret_cast<const char*>(read_region->data()); - size_t read_region_data_length = strnlen(read_region_data, read_length); - local_string.append(read_region_data, read_region_data_length); - if (read_region_data_length < read_length) { - string->swap(local_string); - return true; - } - - if (has_size) { - size -= read_length; - } - read_address = mach_vm_trunc_page(read_address + read_length); - } while ((!has_size || size > 0) && read_address > address); - - LOG(WARNING) << base::StringPrintf("unterminated string at 0x%llx", address); - return false; + memcpy(buffer, memory->data(), size); + return static_cast<ssize_t>(size); } } // namespace crashpad diff --git a/util/mach/task_memory.h b/util/mach/task_memory.h index 118ff0ba..8fc217a6 100644 --- a/util/mach/task_memory.h +++ b/util/mach/task_memory.h @@ -23,12 +23,14 @@ #include "base/mac/scoped_mach_vm.h" #include "base/macros.h" +#include "util/misc/address_types.h" #include "util/misc/initialization_state_dcheck.h" +#include "util/process/process_memory.h" namespace crashpad { //! \brief Accesses the memory of another Mach task. -class TaskMemory { +class TaskMemory : public ProcessMemory { public: //! \brief A memory region mapped from another Mach task. //! @@ -103,23 +105,6 @@ class TaskMemory { //! \return `true` on success, `false` on failure with a message logged. bool Initialize(task_t task); - //! \brief Copies memory from the target task into a caller-provided buffer in - //! the current task. - //! - //! \param[in] address The address, in the target task’s address space, of the - //! memory region to copy. - //! \param[in] size The size, in bytes, of the memory region to copy. \a - //! buffer must be at least this size. - //! \param[out] buffer The buffer into which the contents of the other task’s - //! memory will be copied. - //! - //! \return `true` on success, with \a buffer filled appropriately. `false` on - //! failure, with a warning logged. Failures can occur, for example, when - //! encountering unmapped or unreadable pages. - //! - //! \sa ReadMapped() - bool Read(mach_vm_address_t address, size_t size, void* buffer); - //! \brief Maps memory from the target task into the current task. //! //! This interface is an alternative to Read() that does not require the @@ -134,50 +119,10 @@ class TaskMemory { //! requested. On faliure, `nullptr`, with a warning logged. Failures can //! occur, for example, when encountering unmapped or unreadable pages. std::unique_ptr<MappedMemory> ReadMapped(mach_vm_address_t address, - size_t size); - - //! \brief Reads a `NUL`-terminated C string from the target task into a - //! string in the current task. - //! - //! The length of the string need not be known ahead of time. This method will - //! read contiguous memory until a `NUL` terminator is found. - //! - //! \param[in] address The address, in the target task’s address space, of the - //! string to copy. - //! \param[out] string The string read from the other task. - //! - //! \return `true` on success, with \a string set appropriately. `false` on - //! failure, with a warning logged. Failures can occur, for example, when - //! encountering unmapped or unreadable pages. - //! - //! \sa MappedMemory::ReadCString() - bool ReadCString(mach_vm_address_t address, std::string* string); - - //! \brief Reads a `NUL`-terminated C string from the target task into a - //! string in the current task. - //! - //! \param[in] address The address, in the target task’s address space, of the - //! string to copy. - //! \param[in] size The maximum number of bytes to read. The string is - //! required to be `NUL`-terminated within this many bytes. - //! \param[out] string The string read from the other task. - //! - //! \return `true` on success, with \a string set appropriately. `false` on - //! failure, with a warning logged. Failures can occur, for example, when - //! a `NUL` terminator is not found within \a size bytes, or when - //! encountering unmapped or unreadable pages. - //! - //! \sa MappedMemory::ReadCString() - bool ReadCStringSizeLimited(mach_vm_address_t address, - mach_vm_size_t size, - std::string* string); + size_t size) const; private: - // The common internal implementation shared by the ReadCString*() methods. - bool ReadCStringInternal(mach_vm_address_t address, - bool has_size, - mach_vm_size_t size, - std::string* string); + ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) const override; task_t task_; // weak InitializationStateDcheck initialized_; diff --git a/util/process/process_memory_native.h b/util/process/process_memory_native.h index e81208ee..79cf1e1d 100644 --- a/util/process/process_memory_native.h +++ b/util/process/process_memory_native.h @@ -20,6 +20,8 @@ #include "util/process/process_memory_linux.h" #elif defined(OS_WIN) #include "util/process/process_memory_win.h" +#elif defined(OS_MACOSX) +#include "util/mach/task_memory.h" #endif namespace crashpad { @@ -31,6 +33,8 @@ using ProcessMemoryNative = ProcessMemoryFuchsia; using ProcessMemoryNative = ProcessMemoryLinux; #elif defined(OS_WIN) using ProcessMemoryNative = ProcessMemoryWin; +#elif defined(OS_MACOSX) +using ProcessMemoryNative = TaskMemory; #else #error Port. #endif diff --git a/util/process/process_memory_test.cc b/util/process/process_memory_test.cc index ca1f4973..a824bf63 100644 --- a/util/process/process_memory_test.cc +++ b/util/process/process_memory_test.cc @@ -29,10 +29,75 @@ #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" +#if defined(OS_MACOSX) +#include "test/mac/mach_multiprocess.h" +#endif // defined(OS_MACOSX) + namespace crashpad { namespace test { namespace { +// On macOS the ProcessMemoryTests require accessing the child process' task +// 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_MACOSX) +class MultiprocessAdaptor : public MachMultiprocess { + public: + void SetChildTestMainFunction(const std::string& function_name) { + test_function_ = function_name; + } + + ProcessType ChildProcess() { return ChildTask(); } + + // Helpers to get I/O handles in the child process + static FileHandle OutputHandle() { + CHECK_NE(write_pipe_handle_, -1); + return write_pipe_handle_; + } + + static FileHandle InputHandle() { + CHECK_NE(read_pipe_handle_, -1); + return read_pipe_handle_; + } + + private: + virtual void Parent() = 0; + + void MachMultiprocessParent() override { Parent(); } + + void MachMultiprocessChild() override { + read_pipe_handle_ = ReadPipeHandle(); + write_pipe_handle_ = WritePipeHandle(); + internal::CheckedInvokeMultiprocessChild(test_function_); + } + + std::string test_function_; + + static FileHandle read_pipe_handle_; + static FileHandle write_pipe_handle_; +}; + +FileHandle MultiprocessAdaptor::read_pipe_handle_ = -1; +FileHandle MultiprocessAdaptor::write_pipe_handle_ = -1; +#else +class MultiprocessAdaptor : public MultiprocessExec { + public: + static FileHandle OutputHandle() { + return StdioFileHandle(StdioStream::kStandardOutput); + } + + static FileHandle InputHandle() { + return StdioFileHandle(StdioStream::kStandardInput); + } + + private: + virtual void Parent() = 0; + + void MultiprocessParent() override { Parent(); } +}; +#endif // defined(OS_MACOSX) + void DoChildReadTestSetup(size_t* region_size, std::unique_ptr<char[]>* region) { *region_size = 4 * base::GetPageSize(); @@ -46,17 +111,17 @@ CRASHPAD_CHILD_TEST_MAIN(ReadTestChild) { size_t region_size; std::unique_ptr<char[]> region; DoChildReadTestSetup(®ion_size, ®ion); - FileHandle out = StdioFileHandle(StdioStream::kStandardOutput); + FileHandle out = MultiprocessAdaptor::OutputHandle(); CheckedWriteFile(out, ®ion_size, sizeof(region_size)); VMAddress address = FromPointerCast<VMAddress>(region.get()); CheckedWriteFile(out, &address, sizeof(address)); - CheckedReadFileAtEOF(StdioFileHandle(StdioStream::kStandardInput)); + CheckedReadFileAtEOF(MultiprocessAdaptor::InputHandle()); return 0; } -class ReadTest : public MultiprocessExec { +class ReadTest : public MultiprocessAdaptor { public: - ReadTest() : MultiprocessExec() { + ReadTest() : MultiprocessAdaptor() { SetChildTestMainFunction("ReadTestChild"); } @@ -72,7 +137,7 @@ class ReadTest : public MultiprocessExec { void RunAgainstChild() { Run(); } private: - void MultiprocessParent() override { + void Parent() override { size_t region_size; VMAddress region; ASSERT_TRUE( @@ -183,23 +248,22 @@ CRASHPAD_CHILD_TEST_MAIN(ReadCStringTestChild) { &const_empty, &const_short, &local_empty, &local_short, &long_string); const auto write_address = [](const char* p) { VMAddress address = FromPointerCast<VMAddress>(p); - CheckedWriteFile(StdioFileHandle(StdioStream::kStandardOutput), - &address, - sizeof(address)); + CheckedWriteFile( + MultiprocessAdaptor::OutputHandle(), &address, sizeof(address)); }; write_address(const_empty); write_address(const_short); write_address(local_empty); write_address(local_short); write_address(long_string.c_str()); - CheckedReadFileAtEOF(StdioFileHandle(StdioStream::kStandardInput)); + CheckedReadFileAtEOF(MultiprocessAdaptor::InputHandle()); return 0; } -class ReadCStringTest : public MultiprocessExec { +class ReadCStringTest : public MultiprocessAdaptor { public: ReadCStringTest(bool limit_size) - : MultiprocessExec(), limit_size_(limit_size) { + : MultiprocessAdaptor(), limit_size_(limit_size) { SetChildTestMainFunction("ReadCStringTestChild"); } @@ -221,7 +285,7 @@ class ReadCStringTest : public MultiprocessExec { void RunAgainstChild() { Run(); } private: - void MultiprocessParent() override { + void Parent() override { #define DECLARE_AND_READ_ADDRESS(name) \ VMAddress name; \ ASSERT_TRUE(ReadFileExactly(ReadPipeHandle(), &name, sizeof(name))); @@ -332,24 +396,24 @@ CRASHPAD_CHILD_TEST_MAIN(ReadUnmappedChildMain) { ScopedGuardedPage pages; VMAddress address = reinterpret_cast<VMAddress>(pages.Pointer()); DoReadUnmappedChildMainSetup(pages.Pointer()); - FileHandle out = StdioFileHandle(StdioStream::kStandardOutput); + FileHandle out = MultiprocessAdaptor::OutputHandle(); CheckedWriteFile(out, &address, sizeof(address)); - CheckedReadFileAtEOF(StdioFileHandle(StdioStream::kStandardInput)); + CheckedReadFileAtEOF(MultiprocessAdaptor::InputHandle()); return 0; } // This test only supports running against a child process because // ScopedGuardedPage is not thread-safe. -class ReadUnmappedTest : public MultiprocessExec { +class ReadUnmappedTest : public MultiprocessAdaptor { public: - ReadUnmappedTest() : MultiprocessExec() { + ReadUnmappedTest() : MultiprocessAdaptor() { SetChildTestMainFunction("ReadUnmappedChildMain"); } void RunAgainstChild() { Run(); } private: - void MultiprocessParent() override { + void Parent() override { VMAddress address = 0; ASSERT_TRUE(ReadFileExactly(ReadPipeHandle(), &address, sizeof(address))); DoTest(ChildProcess(), address); @@ -450,28 +514,28 @@ CRASHPAD_CHILD_TEST_MAIN(ReadCStringUnmappedChildMain) { ScopedGuardedPage pages; std::vector<StringDataInChildProcess> strings; DoCStringUnmappedTestSetup(pages.Pointer(), &strings); - FileHandle out = StdioFileHandle(StdioStream::kStandardOutput); + FileHandle out = MultiprocessAdaptor::OutputHandle(); strings[0].Write(out); strings[1].Write(out); strings[2].Write(out); strings[3].Write(out); - CheckedReadFileAtEOF(StdioFileHandle(StdioStream::kStandardInput)); + CheckedReadFileAtEOF(MultiprocessAdaptor::InputHandle()); return 0; } // This test only supports running against a child process because // ScopedGuardedPage is not thread-safe. -class ReadCStringUnmappedTest : public MultiprocessExec { +class ReadCStringUnmappedTest : public MultiprocessAdaptor { public: ReadCStringUnmappedTest(bool limit_size) - : MultiprocessExec(), limit_size_(limit_size) { + : MultiprocessAdaptor(), limit_size_(limit_size) { SetChildTestMainFunction("ReadCStringUnmappedChildMain"); } void RunAgainstChild() { Run(); } private: - void MultiprocessParent() override { + void Parent() override { std::vector<StringDataInChildProcess> strings; strings.push_back(StringDataInChildProcess::Read(ReadPipeHandle())); strings.push_back(StringDataInChildProcess::Read(ReadPipeHandle())); From 4e3be595f36005e6bac25cd5ce7cb424754ff032 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 20 Dec 2018 11:53:33 -0800 Subject: [PATCH 100/401] Delete redundant TaskMemory tests Delete TaskMemory tests made redundant by equivalent ProcessMemoryTests. Some TaskMemory tests are still not redundant because they test TaskMemory::ReadMapped() or they exercise platform- specific behavior like TaskMemory::Read() not being able to read a VM_PROT_NONE page. Bug: crashpad:263 Change-Id: I72a56b4f3564444b02943f11a0069749bf1b074b Reviewed-on: https://chromium-review.googlesource.com/c/1387270 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- util/mach/task_memory_test.cc | 263 ++-------------------------------- 1 file changed, 8 insertions(+), 255 deletions(-) diff --git a/util/mach/task_memory_test.cc b/util/mach/task_memory_test.cc index 904dfca7..019cec21 100644 --- a/util/mach/task_memory_test.cc +++ b/util/mach/task_memory_test.cc @@ -31,7 +31,7 @@ namespace crashpad { namespace test { namespace { -TEST(TaskMemory, ReadSelf) { +TEST(TaskMemory, ReadMappedSelf) { vm_address_t address = 0; constexpr vm_size_t kSize = 4 * PAGE_SIZE; kern_return_t kr = @@ -47,58 +47,43 @@ TEST(TaskMemory, ReadSelf) { TaskMemory memory; ASSERT_TRUE(memory.Initialize(mach_task_self())); - // This tests using both the Read() and ReadMapped() interfaces. std::string result(kSize, '\0'); std::unique_ptr<TaskMemory::MappedMemory> mapped; // Ensure that the entire region can be read. - ASSERT_TRUE(memory.Read(address, kSize, &result[0])); - EXPECT_EQ(memcmp(region, &result[0], kSize), 0); ASSERT_TRUE((mapped = memory.ReadMapped(address, kSize))); EXPECT_EQ(memcmp(region, mapped->data(), kSize), 0); - // Ensure that a read of length 0 succeeds and doesn’t touch the result. + // Ensure that a read of length 0 succeeds and doesn't touch the result. result.assign(kSize, '\0'); std::string zeroes = result; - ASSERT_TRUE(memory.Read(address, 0, &result[0])); - EXPECT_EQ(result, zeroes); ASSERT_TRUE((mapped = memory.ReadMapped(address, 0))); + EXPECT_EQ(result, zeroes); // Ensure that a read starting at an unaligned address works. - ASSERT_TRUE(memory.Read(address + 1, kSize - 1, &result[0])); - EXPECT_EQ(memcmp(region + 1, &result[0], kSize - 1), 0); ASSERT_TRUE((mapped = memory.ReadMapped(address + 1, kSize - 1))); EXPECT_EQ(memcmp(region + 1, mapped->data(), kSize - 1), 0); // Ensure that a read ending at an unaligned address works. - ASSERT_TRUE(memory.Read(address, kSize - 1, &result[0])); - EXPECT_EQ(memcmp(region, &result[0], kSize - 1), 0); ASSERT_TRUE((mapped = memory.ReadMapped(address, kSize - 1))); EXPECT_EQ(memcmp(region, mapped->data(), kSize - 1), 0); // Ensure that a read starting and ending at unaligned addresses works. - ASSERT_TRUE(memory.Read(address + 1, kSize - 2, &result[0])); - EXPECT_EQ(memcmp(region + 1, &result[0], kSize - 2), 0); ASSERT_TRUE((mapped = memory.ReadMapped(address + 1, kSize - 2))); EXPECT_EQ(memcmp(region + 1, mapped->data(), kSize - 2), 0); // Ensure that a read of exactly one page works. - ASSERT_TRUE(memory.Read(address + PAGE_SIZE, PAGE_SIZE, &result[0])); - EXPECT_EQ(memcmp(region + PAGE_SIZE, &result[0], PAGE_SIZE), 0); ASSERT_TRUE((mapped = memory.ReadMapped(address + PAGE_SIZE, PAGE_SIZE))); EXPECT_EQ(memcmp(region + PAGE_SIZE, mapped->data(), PAGE_SIZE), 0); // Ensure that a read of a single byte works. - ASSERT_TRUE(memory.Read(address + 2, 1, &result[0])); - EXPECT_EQ(result[0], region[2]); ASSERT_TRUE((mapped = memory.ReadMapped(address + 2, 1))); EXPECT_EQ(reinterpret_cast<const char*>(mapped->data())[0], region[2]); - // Ensure that a read of length zero works and doesn’t touch the data. + // Ensure that a read of length zero works and doesn't touch the data. result[0] = 'M'; - ASSERT_TRUE(memory.Read(address + 3, 0, &result[0])); - EXPECT_EQ(result[0], 'M'); ASSERT_TRUE((mapped = memory.ReadMapped(address + 3, 0))); + EXPECT_EQ(result[0], 'M'); } TEST(TaskMemory, ReadSelfUnmapped) { @@ -111,7 +96,7 @@ TEST(TaskMemory, ReadSelfUnmapped) { char* region = reinterpret_cast<char*>(address); for (size_t index = 0; index < kSize; ++index) { - // Don’t include any NUL bytes, because ReadCString stops when it encounters + // Don't include any NUL bytes, because ReadCString stops when it encounters // a NUL. region[index] = (index % 255) + 1; } @@ -163,80 +148,6 @@ TEST(TaskMemory, ReadSelfUnmapped) { EXPECT_TRUE((mapped = memory.ReadMapped(address + PAGE_SIZE - 1, 1))); } -// This function consolidates the cast from a char* to mach_vm_address_t in one -// location when reading from the current task. -bool ReadCStringSelf(TaskMemory* memory, - const char* pointer, - std::string* result) { - return memory->ReadCString(FromPointerCast<mach_vm_address_t>(pointer), - result); -} - -TEST(TaskMemory, ReadCStringSelf) { - TaskMemory memory; - ASSERT_TRUE(memory.Initialize(mach_task_self())); - std::string result; - - const char kConstCharEmpty[] = ""; - ASSERT_TRUE(ReadCStringSelf(&memory, kConstCharEmpty, &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kConstCharEmpty); - - const char kConstCharShort[] = "A short const char[]"; - ASSERT_TRUE(ReadCStringSelf(&memory, kConstCharShort, &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, kConstCharShort); - - static const char kStaticConstCharEmpty[] = ""; - ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstCharEmpty, &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kStaticConstCharEmpty); - - static const char kStaticConstCharShort[] = "A short static const char[]"; - ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstCharShort, &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, kStaticConstCharShort); - - constexpr char kConstexprCharEmpty[] = ""; - ASSERT_TRUE(ReadCStringSelf(&memory, kConstexprCharEmpty, &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kConstexprCharEmpty); - - constexpr char kConstexprCharShort[] = "A short constexpr char[]"; - ASSERT_TRUE(ReadCStringSelf(&memory, kConstexprCharShort, &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, kConstexprCharShort); - - static constexpr char kStaticConstexprCharEmpty[] = ""; - ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstexprCharEmpty, &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kStaticConstexprCharEmpty); - - static constexpr char kStaticConstexprCharShort[] = - "A short static constexpr char[]"; - ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstexprCharShort, &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, kStaticConstexprCharShort); - - std::string string_short("A short std::string in a function"); - ASSERT_TRUE(ReadCStringSelf(&memory, &string_short[0], &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, string_short); - - std::string string_long; - constexpr size_t kStringLongSize = 4 * PAGE_SIZE; - for (size_t index = 0; index < kStringLongSize; ++index) { - // Don’t include any NUL bytes, because ReadCString stops when it encounters - // a NUL. - string_long.append(1, (index % 255) + 1); - } - ASSERT_EQ(string_long.size(), kStringLongSize); - ASSERT_TRUE(ReadCStringSelf(&memory, &string_long[0], &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result.size(), kStringLongSize); - EXPECT_EQ(result, string_long); -} - TEST(TaskMemory, ReadCStringSelfUnmapped) { vm_address_t address = 0; constexpr vm_size_t kSize = 2 * PAGE_SIZE; @@ -247,7 +158,7 @@ TEST(TaskMemory, ReadCStringSelfUnmapped) { char* region = reinterpret_cast<char*>(address); for (size_t index = 0; index < kSize; ++index) { - // Don’t include any NUL bytes, because ReadCString stops when it encounters + // Don't include any NUL bytes, because ReadCString stops when it encounters // a NUL. region[index] = (index % 255) + 1; } @@ -291,164 +202,6 @@ TEST(TaskMemory, ReadCStringSelfUnmapped) { EXPECT_EQ(result, region); } -// This function consolidates the cast from a char* to mach_vm_address_t in one -// location when reading from the current task. -bool ReadCStringSizeLimitedSelf(TaskMemory* memory, - const char* pointer, - size_t size, - std::string* result) { - return memory->ReadCStringSizeLimited( - FromPointerCast<mach_vm_address_t>(pointer), size, result); -} - -TEST(TaskMemory, ReadCStringSizeLimited_ConstCharEmpty) { - TaskMemory memory; - ASSERT_TRUE(memory.Initialize(mach_task_self())); - std::string result; - - static constexpr char kConstCharEmpty[] = ""; - ASSERT_TRUE(ReadCStringSizeLimitedSelf( - &memory, kConstCharEmpty, arraysize(kConstCharEmpty), &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kConstCharEmpty); - - result.clear(); - ASSERT_TRUE(ReadCStringSizeLimitedSelf( - &memory, kConstCharEmpty, arraysize(kConstCharEmpty) + 1, &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kConstCharEmpty); - - result.clear(); - EXPECT_FALSE( - ReadCStringSizeLimitedSelf(&memory, kConstCharEmpty, 0, &result)); -} - -TEST(TaskMemory, ReadCStringSizeLimited_ConstCharShort) { - TaskMemory memory; - ASSERT_TRUE(memory.Initialize(mach_task_self())); - std::string result; - - static constexpr char kConstCharShort[] = "A short const char[]"; - ASSERT_TRUE(ReadCStringSizeLimitedSelf( - &memory, kConstCharShort, arraysize(kConstCharShort), &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, kConstCharShort); - - result.clear(); - ASSERT_TRUE(ReadCStringSizeLimitedSelf( - &memory, kConstCharShort, arraysize(kConstCharShort) + 1, &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, kConstCharShort); - - EXPECT_FALSE(ReadCStringSizeLimitedSelf( - &memory, kConstCharShort, arraysize(kConstCharShort) - 1, &result)); -} - -TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharEmpty) { - TaskMemory memory; - ASSERT_TRUE(memory.Initialize(mach_task_self())); - std::string result; - - static constexpr char kStaticConstCharEmpty[] = ""; - ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory, - kStaticConstCharEmpty, - arraysize(kStaticConstCharEmpty), - &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kStaticConstCharEmpty); - - result.clear(); - ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory, - kStaticConstCharEmpty, - arraysize(kStaticConstCharEmpty) + 1, - &result)); - EXPECT_TRUE(result.empty()); - EXPECT_EQ(result, kStaticConstCharEmpty); - - result.clear(); - ASSERT_FALSE( - ReadCStringSizeLimitedSelf(&memory, kStaticConstCharEmpty, 0, &result)); -} - -TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharShort) { - TaskMemory memory; - ASSERT_TRUE(memory.Initialize(mach_task_self())); - std::string result; - - static constexpr char kStaticConstCharShort[] = - "A short static constexpr char[]"; - ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory, - kStaticConstCharShort, - arraysize(kStaticConstCharShort), - &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, kStaticConstCharShort); - - result.clear(); - ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory, - kStaticConstCharShort, - arraysize(kStaticConstCharShort) + 1, - &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, kStaticConstCharShort); - - ASSERT_FALSE(ReadCStringSizeLimitedSelf(&memory, - kStaticConstCharShort, - arraysize(kStaticConstCharShort) - 1, - &result)); -} - -TEST(TaskMemory, ReadCStringSizeLimited_StringShort) { - TaskMemory memory; - ASSERT_TRUE(memory.Initialize(mach_task_self())); - std::string result; - - std::string string_short("A short std::string in a function"); - ASSERT_TRUE(ReadCStringSizeLimitedSelf( - &memory, &string_short[0], string_short.size() + 1, &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, string_short); - - result.clear(); - ASSERT_TRUE(ReadCStringSizeLimitedSelf( - &memory, &string_short[0], string_short.size() + 2, &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result, string_short); - - ASSERT_FALSE(ReadCStringSizeLimitedSelf( - &memory, &string_short[0], string_short.size(), &result)); -} - -TEST(TaskMemory, ReadCStringSizeLimited_StringLong) { - TaskMemory memory; - ASSERT_TRUE(memory.Initialize(mach_task_self())); - std::string result; - - std::string string_long; - constexpr size_t kStringLongSize = 4 * PAGE_SIZE; - for (size_t index = 0; index < kStringLongSize; ++index) { - // Don’t include any NUL bytes, because ReadCString stops when it encounters - // a NUL. - string_long.append(1, (index % 255) + 1); - } - ASSERT_EQ(string_long.size(), kStringLongSize); - ASSERT_TRUE(ReadCStringSizeLimitedSelf( - &memory, &string_long[0], string_long.size() + 1, &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result.size(), kStringLongSize); - EXPECT_EQ(result, string_long); - - result.clear(); - ASSERT_TRUE(ReadCStringSizeLimitedSelf( - &memory, &string_long[0], string_long.size() + 2, &result)); - EXPECT_FALSE(result.empty()); - EXPECT_EQ(result.size(), kStringLongSize); - EXPECT_EQ(result, string_long); - - ASSERT_FALSE(ReadCStringSizeLimitedSelf( - &memory, &string_long[0], string_long.size(), &result)); -} - bool IsAddressMapped(vm_address_t address) { vm_address_t region_address = address; vm_size_t region_size; @@ -484,7 +237,7 @@ TEST(TaskMemory, MappedMemoryDeallocates) { // releases the mapped memory that it owned. Technically, this test is not // valid because after the mapping is released, something else (on another // thread) might wind up mapped in the same address. In the test environment, - // hopefully there are either no other threads or they’re all quiescent, so + // hopefully there are either no other threads or they're all quiescent, so // nothing else should wind up mapped in the address. TaskMemory memory; From 3f7d4d7d093c4e7d9f894911b4cc71987f009d27 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 20 Dec 2018 11:57:49 -0800 Subject: [PATCH 101/401] Break out redundant tests into a routine Bug: crashpad:263 Change-Id: Ib6f05f5e7b91a434e54e0a8d6cd55078b2bf84f5 Reviewed-on: https://chromium-review.googlesource.com/c/1387269 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/process/process_memory_test.cc | 68 ++++++++++------------------- 1 file changed, 23 insertions(+), 45 deletions(-) diff --git a/util/process/process_memory_test.cc b/util/process/process_memory_test.cc index a824bf63..cb592a03 100644 --- a/util/process/process_memory_test.cc +++ b/util/process/process_memory_test.cc @@ -304,6 +304,23 @@ class ReadCStringTest : public MultiprocessAdaptor { long_string_address); } + void Compare(ProcessMemory& memory, VMAddress address, const char* str) { + std::string result; + if (limit_size_) { + ASSERT_TRUE( + memory.ReadCStringSizeLimited(address, strlen(str) + 1, &result)); + EXPECT_EQ(result, str); + ASSERT_TRUE( + memory.ReadCStringSizeLimited(address, strlen(str) + 2, &result)); + EXPECT_EQ(result, str); + EXPECT_FALSE( + memory.ReadCStringSizeLimited(address, strlen(str), &result)); + } else { + ASSERT_TRUE(memory.ReadCString(address, &result)); + EXPECT_EQ(result, str); + } + } + void DoTest(ProcessType process, VMAddress const_empty_address, VMAddress const_short_address, @@ -313,51 +330,12 @@ class ReadCStringTest : public MultiprocessAdaptor { ProcessMemoryNative memory; ASSERT_TRUE(memory.Initialize(process)); - std::string result; - - if (limit_size_) { - ASSERT_TRUE(memory.ReadCStringSizeLimited( - const_empty_address, arraysize(kConstCharEmpty), &result)); - EXPECT_EQ(result, kConstCharEmpty); - - ASSERT_TRUE(memory.ReadCStringSizeLimited( - const_short_address, arraysize(kConstCharShort), &result)); - EXPECT_EQ(result, kConstCharShort); - EXPECT_FALSE(memory.ReadCStringSizeLimited( - const_short_address, arraysize(kConstCharShort) - 1, &result)); - - ASSERT_TRUE( - memory.ReadCStringSizeLimited(local_empty_address, 1, &result)); - EXPECT_EQ(result, ""); - - ASSERT_TRUE(memory.ReadCStringSizeLimited( - local_short_address, strlen(SHORT_LOCAL_STRING) + 1, &result)); - EXPECT_EQ(result, SHORT_LOCAL_STRING); - EXPECT_FALSE(memory.ReadCStringSizeLimited( - local_short_address, strlen(SHORT_LOCAL_STRING), &result)); - - std::string long_string_for_comparison = MakeLongString(); - ASSERT_TRUE(memory.ReadCStringSizeLimited( - long_string_address, long_string_for_comparison.size() + 1, &result)); - EXPECT_EQ(result, long_string_for_comparison); - EXPECT_FALSE(memory.ReadCStringSizeLimited( - long_string_address, long_string_for_comparison.size(), &result)); - } else { - ASSERT_TRUE(memory.ReadCString(const_empty_address, &result)); - EXPECT_EQ(result, kConstCharEmpty); - - ASSERT_TRUE(memory.ReadCString(const_short_address, &result)); - EXPECT_EQ(result, kConstCharShort); - - ASSERT_TRUE(memory.ReadCString(local_empty_address, &result)); - EXPECT_EQ(result, ""); - - ASSERT_TRUE(memory.ReadCString(local_short_address, &result)); - EXPECT_EQ(result, SHORT_LOCAL_STRING); - - ASSERT_TRUE(memory.ReadCString(long_string_address, &result)); - EXPECT_EQ(result, MakeLongString()); - } + Compare(memory, const_empty_address, kConstCharEmpty); + Compare(memory, const_short_address, kConstCharShort); + Compare(memory, local_empty_address, ""); + Compare(memory, local_short_address, SHORT_LOCAL_STRING); + std::string long_string_for_comparison = MakeLongString(); + Compare(memory, long_string_address, long_string_for_comparison.c_str()); } const bool limit_size_; From 3b9e3aad1b99cad7386d898aad19f7ee3bbbb385 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 20 Dec 2018 13:12:55 -0800 Subject: [PATCH 102/401] Move and rename TaskMemory to ProcessMemoryMac Bug: crashpad:263 Change-Id: I5efa4fe26f09c8b8a8db6dbcedc416724404b894 Reviewed-on: https://chromium-review.googlesource.com/c/1387884 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- .../mac/mach_o_image_annotations_reader.cc | 1 - .../mac/mach_o_image_symbol_table_reader.cc | 4 +-- .../mac/mach_o_image_symbol_table_reader.h | 2 +- snapshot/mac/process_reader_mac.cc | 6 ++-- snapshot/mac/process_reader_mac.h | 6 ++-- snapshot/mac/process_types.cc | 2 +- snapshot/mac/process_types/custom.cc | 18 +++++----- util/BUILD.gn | 6 ++-- .../process_memory_mac.cc} | 29 ++++++++------- .../process_memory_mac.h} | 16 ++++----- .../process_memory_mac_test.cc} | 36 +++++++++---------- util/process/process_memory_native.h | 4 +-- util/util.gyp | 4 +-- util/util_test.gyp | 2 +- 14 files changed, 67 insertions(+), 69 deletions(-) rename util/{mach/task_memory.cc => process/process_memory_mac.cc} (79%) rename util/{mach/task_memory.h => process/process_memory_mac.h} (93%) rename util/{mach/task_memory_test.cc => process/process_memory_mac_test.cc} (93%) diff --git a/snapshot/mac/mach_o_image_annotations_reader.cc b/snapshot/mac/mach_o_image_annotations_reader.cc index b02acaea..e730b511 100644 --- a/snapshot/mac/mach_o_image_annotations_reader.cc +++ b/snapshot/mac/mach_o_image_annotations_reader.cc @@ -26,7 +26,6 @@ #include "snapshot/mac/mach_o_image_reader.h" #include "snapshot/mac/process_reader_mac.h" #include "snapshot/snapshot_constants.h" -#include "util/mach/task_memory.h" #include "util/stdlib/strnlen.h" namespace crashpad { diff --git a/snapshot/mac/mach_o_image_symbol_table_reader.cc b/snapshot/mac/mach_o_image_symbol_table_reader.cc index 361253ce..cbdac402 100644 --- a/snapshot/mac/mach_o_image_symbol_table_reader.cc +++ b/snapshot/mac/mach_o_image_symbol_table_reader.cc @@ -23,7 +23,7 @@ #include "base/strings/stringprintf.h" #include "util/mac/checked_mach_address_range.h" -#include "util/mach/task_memory.h" +#include "util/process/process_memory_mac.h" namespace crashpad { @@ -108,7 +108,7 @@ class MachOImageSymbolTableReaderInitializer { return false; } - std::unique_ptr<TaskMemory::MappedMemory> string_table; + std::unique_ptr<ProcessMemoryMac::MappedMemory> string_table; for (size_t symbol_index = 0; symbol_index < symbol_count; ++symbol_index) { const process_types::nlist& symbol = symbols[symbol_index]; std::string symbol_info = base::StringPrintf(", symbol index %zu%s", diff --git a/snapshot/mac/mach_o_image_symbol_table_reader.h b/snapshot/mac/mach_o_image_symbol_table_reader.h index 841b479a..b1bcc3a2 100644 --- a/snapshot/mac/mach_o_image_symbol_table_reader.h +++ b/snapshot/mac/mach_o_image_symbol_table_reader.h @@ -58,7 +58,7 @@ class MachOImageSymbolTableReader { // there aren’t expected to be very many of those that performance would // become a problem. In reality, std::unordered_map does not appear to provide // a performance advantage. It appears that the memory copies currently done - // by TaskMemory::Read() have substantially more impact on symbol table + // by ProcessMemoryMac::Read() have substantially more impact on symbol table // operations. // // This is public so that the type is available to diff --git a/snapshot/mac/process_reader_mac.cc b/snapshot/mac/process_reader_mac.cc index 4850bbab..61dc3a1f 100644 --- a/snapshot/mac/process_reader_mac.cc +++ b/snapshot/mac/process_reader_mac.cc @@ -92,7 +92,7 @@ ProcessReaderMac::ProcessReaderMac() threads_(), modules_(), module_readers_(), - task_memory_(), + process_memory_(), task_(TASK_NULL), initialized_(), is_64_bit_(false), @@ -113,7 +113,7 @@ bool ProcessReaderMac::Initialize(task_t task) { return false; } - if (!task_memory_.Initialize(task)) { + if (!process_memory_.Initialize(task)) { return false; } @@ -443,7 +443,7 @@ void ProcessReaderMac::InitializeModules() { Module module; module.timestamp = image_info.imageFileModDate; - if (!task_memory_.ReadCString(image_info.imageFilePath, &module.name)) { + if (!process_memory_.ReadCString(image_info.imageFilePath, &module.name)) { LOG(WARNING) << "could not read dyld_image_info::imageFilePath"; // Proceed anyway with an empty module name. } diff --git a/snapshot/mac/process_reader_mac.h b/snapshot/mac/process_reader_mac.h index 8a5b2c80..9435b057 100644 --- a/snapshot/mac/process_reader_mac.h +++ b/snapshot/mac/process_reader_mac.h @@ -27,9 +27,9 @@ #include "base/macros.h" #include "build/build_config.h" -#include "util/mach/task_memory.h" #include "util/misc/initialization_state_dcheck.h" #include "util/posix/process_info.h" +#include "util/process/process_memory_mac.h" namespace crashpad { @@ -138,7 +138,7 @@ class ProcessReaderMac { bool CPUTimes(timeval* user_time, timeval* system_time) const; //! \return Accesses the memory of the target task. - TaskMemory* Memory() { return &task_memory_; } + ProcessMemoryMac* Memory() { return &process_memory_; } //! \return The threads that are in the task (process). The first element (at //! index `0`) corresponds to the main thread. @@ -232,7 +232,7 @@ class ProcessReaderMac { std::vector<Thread> threads_; // owns send rights std::vector<Module> modules_; std::vector<std::unique_ptr<MachOImageReader>> module_readers_; - TaskMemory task_memory_; + ProcessMemoryMac process_memory_; task_t task_; // weak InitializationStateDcheck initialized_; diff --git a/snapshot/mac/process_types.cc b/snapshot/mac/process_types.cc index 65c39ea5..cbb114d7 100644 --- a/snapshot/mac/process_types.cc +++ b/snapshot/mac/process_types.cc @@ -22,7 +22,7 @@ #include "base/macros.h" #include "snapshot/mac/process_types/internal.h" -#include "util/mach/task_memory.h" +#include "util/process/process_memory_mac.h" namespace crashpad { namespace { diff --git a/snapshot/mac/process_types/custom.cc b/snapshot/mac/process_types/custom.cc index 7c7b172a..7a207e98 100644 --- a/snapshot/mac/process_types/custom.cc +++ b/snapshot/mac/process_types/custom.cc @@ -25,7 +25,7 @@ #include "base/numerics/safe_math.h" #include "base/strings/stringprintf.h" #include "snapshot/mac/process_types/internal.h" -#include "util/mach/task_memory.h" +#include "util/process/process_memory_mac.h" #if !DOXYGEN @@ -36,13 +36,13 @@ namespace internal { namespace { template <typename T> -bool ReadIntoAndZero(TaskMemory* task_memory, +bool ReadIntoAndZero(ProcessMemoryMac* process_memory, mach_vm_address_t address, mach_vm_size_t size, T* specific) { DCHECK_LE(size, sizeof(*specific)); - if (!task_memory->Read(address, size, specific)) { + if (!process_memory->Read(address, size, specific)) { return false; } @@ -84,14 +84,14 @@ bool ReadIntoVersioned(ProcessReaderMac* process_reader, return false; } - TaskMemory* task_memory = process_reader->Memory(); + ProcessMemoryMac* process_memory = process_reader->Memory(); decltype(specific->version) version; - if (!task_memory->Read(field_address, sizeof(version), &version)) { + if (!process_memory->Read(field_address, sizeof(version), &version)) { return false; } const size_t size = T::ExpectedSizeForVersion(version); - return ReadIntoAndZero(task_memory, address, size, specific); + return ReadIntoAndZero(process_memory, address, size, specific); } template <typename T> @@ -103,9 +103,9 @@ bool ReadIntoSized(ProcessReaderMac* process_reader, return false; } - TaskMemory* task_memory = process_reader->Memory(); + ProcessMemoryMac* process_memory = process_reader->Memory(); decltype(specific->size) size; - if (!task_memory->Read(address + offsetof(T, size), sizeof(size), &size)) { + if (!process_memory->Read(address + offsetof(T, size), sizeof(size), &size)) { return false; } @@ -115,7 +115,7 @@ bool ReadIntoSized(ProcessReaderMac* process_reader, } size = std::min(static_cast<size_t>(size), sizeof(*specific)); - return ReadIntoAndZero(task_memory, address, size, specific); + return ReadIntoAndZero(process_memory, address, size, specific); } } // namespace diff --git a/util/BUILD.gn b/util/BUILD.gn index e43c42f0..c7c6837b 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -244,13 +244,13 @@ static_library("util") { "mach/symbolic_constants_mach.h", "mach/task_for_pid.cc", "mach/task_for_pid.h", - "mach/task_memory.cc", - "mach/task_memory.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", ] sources += get_target_outputs(":mig") @@ -605,8 +605,8 @@ source_set("util_test") { "mach/notify_server_test.cc", "mach/scoped_task_suspend_test.cc", "mach/symbolic_constants_mach_test.cc", - "mach/task_memory_test.cc", "misc/capture_context_test_util_mac.cc", + "process/process_memory_mac_test.cc", ] } diff --git a/util/mach/task_memory.cc b/util/process/process_memory_mac.cc similarity index 79% rename from util/mach/task_memory.cc rename to util/process/process_memory_mac.cc index eb8b1f57..eba1f201 100644 --- a/util/mach/task_memory.cc +++ b/util/process/process_memory_mac.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "util/mach/task_memory.h" +#include "util/process/process_memory_mac.h" #include <mach/mach_vm.h> #include <string.h> @@ -26,11 +26,10 @@ namespace crashpad { -TaskMemory::MappedMemory::~MappedMemory() { -} +ProcessMemoryMac::MappedMemory::~MappedMemory() {} -bool TaskMemory::MappedMemory::ReadCString( - size_t offset, std::string* string) const { +bool ProcessMemoryMac::MappedMemory::ReadCString(size_t offset, + std::string* string) const { if (offset >= user_size_) { LOG(WARNING) << "offset out of range"; return false; @@ -48,10 +47,10 @@ bool TaskMemory::MappedMemory::ReadCString( return true; } -TaskMemory::MappedMemory::MappedMemory(vm_address_t vm_address, - size_t vm_size, - size_t user_offset, - size_t user_size) +ProcessMemoryMac::MappedMemory::MappedMemory(vm_address_t vm_address, + size_t vm_size, + size_t user_offset, + size_t user_size) : vm_(vm_address, vm_size), data_(reinterpret_cast<const void*>(vm_address + user_offset)), user_size_(user_size) { @@ -64,16 +63,16 @@ TaskMemory::MappedMemory::MappedMemory(vm_address_t vm_address, DCHECK_LE(user_end, vm_end); } -TaskMemory::TaskMemory() : task_(TASK_NULL), initialized_() {} +ProcessMemoryMac::ProcessMemoryMac() : task_(TASK_NULL), initialized_() {} -bool TaskMemory::Initialize(task_t task) { +bool ProcessMemoryMac::Initialize(task_t task) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); task_ = task; INITIALIZATION_STATE_SET_VALID(initialized_); return true; } -std::unique_ptr<TaskMemory::MappedMemory> TaskMemory::ReadMapped( +std::unique_ptr<ProcessMemoryMac::MappedMemory> ProcessMemoryMac::ReadMapped( mach_vm_address_t address, size_t size) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); @@ -101,9 +100,9 @@ std::unique_ptr<TaskMemory::MappedMemory> TaskMemory::ReadMapped( new MappedMemory(region, region_size, address - region_address, size)); } -ssize_t TaskMemory::ReadUpTo(VMAddress address, - size_t size, - void* buffer) const { +ssize_t ProcessMemoryMac::ReadUpTo(VMAddress address, + size_t size, + void* buffer) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); DCHECK_LE(size, (size_t)std::numeric_limits<ssize_t>::max()); diff --git a/util/mach/task_memory.h b/util/process/process_memory_mac.h similarity index 93% rename from util/mach/task_memory.h rename to util/process/process_memory_mac.h index 8fc217a6..214e4890 100644 --- a/util/mach/task_memory.h +++ b/util/process/process_memory_mac.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CRASHPAD_UTIL_MACH_TASK_MEMORY_H_ -#define CRASHPAD_UTIL_MACH_TASK_MEMORY_H_ +#ifndef CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_MAC_H_ +#define CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_MAC_H_ #include <mach/mach.h> #include <sys/types.h> @@ -30,7 +30,7 @@ namespace crashpad { //! \brief Accesses the memory of another Mach task. -class TaskMemory : public ProcessMemory { +class ProcessMemoryMac : public ProcessMemory { public: //! \brief A memory region mapped from another Mach task. //! @@ -85,13 +85,13 @@ class TaskMemory : public ProcessMemory { size_t user_size_; // The outer class needs to be able to call this class’ private constructor. - friend class TaskMemory; + friend class ProcessMemoryMac; DISALLOW_COPY_AND_ASSIGN(MappedMemory); }; - TaskMemory(); - ~TaskMemory() {} + ProcessMemoryMac(); + ~ProcessMemoryMac() {} //! \brief Initializes this object to read the memory of a task with the //! provided task port. @@ -127,9 +127,9 @@ class TaskMemory : public ProcessMemory { task_t task_; // weak InitializationStateDcheck initialized_; - DISALLOW_COPY_AND_ASSIGN(TaskMemory); + DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMac); }; } // namespace crashpad -#endif // CRASHPAD_UTIL_MACH_TASK_MEMORY_H_ +#endif // CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_MAC_H_ diff --git a/util/mach/task_memory_test.cc b/util/process/process_memory_mac_test.cc similarity index 93% rename from util/mach/task_memory_test.cc rename to util/process/process_memory_mac_test.cc index 019cec21..d801bb14 100644 --- a/util/mach/task_memory_test.cc +++ b/util/process/process_memory_mac_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "util/mach/task_memory.h" +#include "util/process/process_memory_mac.h" #include <mach/mach.h> #include <string.h> @@ -31,7 +31,7 @@ namespace crashpad { namespace test { namespace { -TEST(TaskMemory, ReadMappedSelf) { +TEST(ProcessMemoryMac, ReadMappedSelf) { vm_address_t address = 0; constexpr vm_size_t kSize = 4 * PAGE_SIZE; kern_return_t kr = @@ -44,11 +44,11 @@ TEST(TaskMemory, ReadMappedSelf) { region[index] = (index % 256) ^ ((index >> 8) % 256); } - TaskMemory memory; + ProcessMemoryMac memory; ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result(kSize, '\0'); - std::unique_ptr<TaskMemory::MappedMemory> mapped; + std::unique_ptr<ProcessMemoryMac::MappedMemory> mapped; // Ensure that the entire region can be read. ASSERT_TRUE((mapped = memory.ReadMapped(address, kSize))); @@ -86,7 +86,7 @@ TEST(TaskMemory, ReadMappedSelf) { EXPECT_EQ(result[0], 'M'); } -TEST(TaskMemory, ReadSelfUnmapped) { +TEST(ProcessMemoryMac, ReadSelfUnmapped) { vm_address_t address = 0; constexpr vm_size_t kSize = 2 * PAGE_SIZE; kern_return_t kr = @@ -105,7 +105,7 @@ TEST(TaskMemory, ReadSelfUnmapped) { mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE); ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_protect"); - TaskMemory memory; + ProcessMemoryMac memory; ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result(kSize, '\0'); @@ -117,7 +117,7 @@ TEST(TaskMemory, ReadSelfUnmapped) { EXPECT_TRUE(memory.Read(address + PAGE_SIZE - 1, 1, &result[0])); // Do the same thing with the ReadMapped() interface. - std::unique_ptr<TaskMemory::MappedMemory> mapped; + std::unique_ptr<ProcessMemoryMac::MappedMemory> mapped; EXPECT_FALSE((mapped = memory.ReadMapped(address, kSize))); EXPECT_FALSE((mapped = memory.ReadMapped(address + 1, kSize - 1))); EXPECT_FALSE((mapped = memory.ReadMapped(address + PAGE_SIZE, 1))); @@ -148,7 +148,7 @@ TEST(TaskMemory, ReadSelfUnmapped) { EXPECT_TRUE((mapped = memory.ReadMapped(address + PAGE_SIZE - 1, 1))); } -TEST(TaskMemory, ReadCStringSelfUnmapped) { +TEST(ProcessMemoryMac, ReadCStringSelfUnmapped) { vm_address_t address = 0; constexpr vm_size_t kSize = 2 * PAGE_SIZE; kern_return_t kr = @@ -167,7 +167,7 @@ TEST(TaskMemory, ReadCStringSelfUnmapped) { mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE); ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "vm_protect"); - TaskMemory memory; + ProcessMemoryMac memory; ASSERT_TRUE(memory.Initialize(mach_task_self())); std::string result; EXPECT_FALSE(memory.ReadCString(address, &result)); @@ -232,17 +232,17 @@ bool IsAddressMapped(vm_address_t address) { return false; } -TEST(TaskMemory, MappedMemoryDeallocates) { - // This tests that once a TaskMemory::MappedMemory object is destroyed, it - // releases the mapped memory that it owned. Technically, this test is not +TEST(ProcessMemoryMac, MappedMemoryDeallocates) { + // This tests that once a ProcessMemoryMac::MappedMemory object is destroyed, + // it releases the mapped memory that it owned. Technically, this test is not // valid because after the mapping is released, something else (on another // thread) might wind up mapped in the same address. In the test environment, // hopefully there are either no other threads or they're all quiescent, so // nothing else should wind up mapped in the address. - TaskMemory memory; + ProcessMemoryMac memory; ASSERT_TRUE(memory.Initialize(mach_task_self())); - std::unique_ptr<TaskMemory::MappedMemory> mapped; + std::unique_ptr<ProcessMemoryMac::MappedMemory> mapped; static constexpr char kTestBuffer[] = "hello!"; mach_vm_address_t test_address = @@ -276,11 +276,11 @@ TEST(TaskMemory, MappedMemoryDeallocates) { EXPECT_FALSE(IsAddressMapped(mapped_last_address)); } -TEST(TaskMemory, MappedMemoryReadCString) { - // This tests the behavior of TaskMemory::MappedMemory::ReadCString(). - TaskMemory memory; +TEST(ProcessMemoryMac, MappedMemoryReadCString) { + // This tests the behavior of ProcessMemoryMac::MappedMemory::ReadCString(). + ProcessMemoryMac memory; ASSERT_TRUE(memory.Initialize(mach_task_self())); - std::unique_ptr<TaskMemory::MappedMemory> mapped; + std::unique_ptr<ProcessMemoryMac::MappedMemory> mapped; static constexpr char kTestBuffer[] = "0\0" "2\0" "45\0" "789"; const mach_vm_address_t kTestAddress = diff --git a/util/process/process_memory_native.h b/util/process/process_memory_native.h index 79cf1e1d..39bfc893 100644 --- a/util/process/process_memory_native.h +++ b/util/process/process_memory_native.h @@ -21,7 +21,7 @@ #elif defined(OS_WIN) #include "util/process/process_memory_win.h" #elif defined(OS_MACOSX) -#include "util/mach/task_memory.h" +#include "util/process/process_memory_mac.h" #endif namespace crashpad { @@ -34,7 +34,7 @@ using ProcessMemoryNative = ProcessMemoryLinux; #elif defined(OS_WIN) using ProcessMemoryNative = ProcessMemoryWin; #elif defined(OS_MACOSX) -using ProcessMemoryNative = TaskMemory; +using ProcessMemoryNative = ProcessMemoryMac; #else #error Port. #endif diff --git a/util/util.gyp b/util/util.gyp index 60e91304..dc82287e 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -124,8 +124,6 @@ 'mach/symbolic_constants_mach.h', 'mach/task_for_pid.cc', 'mach/task_for_pid.h', - 'mach/task_memory.cc', - 'mach/task_memory.h', 'misc/address_sanitizer.h', 'misc/address_types.h', 'misc/arraysize_unsafe.h', @@ -215,6 +213,8 @@ 'process/process_memory.h', 'process/process_memory_linux.cc', 'process/process_memory_linux.h', + 'process/process_memory_mac.cc', + 'process/process_memory_mac.h', 'process/process_memory_native.h', 'process/process_memory_range.cc', 'process/process_memory_range.h', diff --git a/util/util_test.gyp b/util/util_test.gyp index 485ed663..b3c8d419 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -65,7 +65,6 @@ 'mach/notify_server_test.cc', 'mach/scoped_task_suspend_test.cc', 'mach/symbolic_constants_mach_test.cc', - 'mach/task_memory_test.cc', 'misc/arraysize_unsafe_test.cc', 'misc/capture_context_test.cc', 'misc/capture_context_test_util.h', @@ -98,6 +97,7 @@ 'posix/scoped_mmap_test.cc', 'posix/signals_test.cc', 'posix/symbolic_constants_posix_test.cc', + 'process/process_memory_mac_test.cc', 'process/process_memory_range_test.cc', 'process/process_memory_test.cc', 'stdlib/aligned_allocator_test.cc', From fccd9c09c0b6f96543bf1426a941ba561262a340 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 20 Dec 2018 13:40:53 -0800 Subject: [PATCH 103/401] Implement ProcessSnapshotMac::Memory() Plumb ProcessReaderMac::Memory() through to ProcessSnapshotMac::Memory() and add consts where necessary to accomodate the type signature of ProcessSnapshot::Memory(). Bug: crashpad:263 Change-Id: I2608979918bc201ae3561483ea52ed2092cbc1e2 Reviewed-on: https://chromium-review.googlesource.com/c/1387924 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- snapshot/mac/process_reader_mac.h | 2 +- snapshot/mac/process_snapshot_mac.cc | 3 +-- snapshot/mac/process_types/custom.cc | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/snapshot/mac/process_reader_mac.h b/snapshot/mac/process_reader_mac.h index 9435b057..9feb8b07 100644 --- a/snapshot/mac/process_reader_mac.h +++ b/snapshot/mac/process_reader_mac.h @@ -138,7 +138,7 @@ class ProcessReaderMac { bool CPUTimes(timeval* user_time, timeval* system_time) const; //! \return Accesses the memory of the target task. - ProcessMemoryMac* Memory() { return &process_memory_; } + const ProcessMemoryMac* Memory() const { return &process_memory_; } //! \return The threads that are in the task (process). The first element (at //! index `0`) corresponds to the main thread. diff --git a/snapshot/mac/process_snapshot_mac.cc b/snapshot/mac/process_snapshot_mac.cc index 68837ff4..528e9213 100644 --- a/snapshot/mac/process_snapshot_mac.cc +++ b/snapshot/mac/process_snapshot_mac.cc @@ -219,8 +219,7 @@ std::vector<const MemorySnapshot*> ProcessSnapshotMac::ExtraMemory() const { const ProcessMemory* ProcessSnapshotMac::Memory() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/263 - return nullptr; + return process_reader_.Memory(); } void ProcessSnapshotMac::InitializeThreads() { diff --git a/snapshot/mac/process_types/custom.cc b/snapshot/mac/process_types/custom.cc index 7a207e98..90209654 100644 --- a/snapshot/mac/process_types/custom.cc +++ b/snapshot/mac/process_types/custom.cc @@ -36,7 +36,7 @@ namespace internal { namespace { template <typename T> -bool ReadIntoAndZero(ProcessMemoryMac* process_memory, +bool ReadIntoAndZero(const ProcessMemoryMac* process_memory, mach_vm_address_t address, mach_vm_size_t size, T* specific) { @@ -84,7 +84,7 @@ bool ReadIntoVersioned(ProcessReaderMac* process_reader, return false; } - ProcessMemoryMac* process_memory = process_reader->Memory(); + const ProcessMemoryMac* process_memory = process_reader->Memory(); decltype(specific->version) version; if (!process_memory->Read(field_address, sizeof(version), &version)) { return false; @@ -103,7 +103,7 @@ bool ReadIntoSized(ProcessReaderMac* process_reader, return false; } - ProcessMemoryMac* process_memory = process_reader->Memory(); + const ProcessMemoryMac* process_memory = process_reader->Memory(); decltype(specific->size) size; if (!process_memory->Read(address + offsetof(T, size), sizeof(size), &size)) { return false; From abfad376ab08dfa42a984353004d72a38cadb198 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 20 Dec 2018 14:42:17 -0800 Subject: [PATCH 104/401] Add missing build/build_config.h includes Didn't notice these until I hit presubmit in chromium. Bug: crashpad:263 Change-Id: I7d86c508928c95a65b7972a19fbdf3bd19c9b29b Reviewed-on: https://chromium-review.googlesource.com/c/1387885 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- test/multiprocess_exec_posix.cc | 1 + util/process/process_memory_test.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/test/multiprocess_exec_posix.cc b/test/multiprocess_exec_posix.cc index bf4263a2..534013ca 100644 --- a/test/multiprocess_exec_posix.cc +++ b/test/multiprocess_exec_posix.cc @@ -20,6 +20,7 @@ #include <unistd.h> #include "base/posix/eintr_wrapper.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" #include "util/misc/scoped_forbid_return.h" diff --git a/util/process/process_memory_test.cc b/util/process/process_memory_test.cc index cb592a03..3f5db24f 100644 --- a/util/process/process_memory_test.cc +++ b/util/process/process_memory_test.cc @@ -19,6 +19,7 @@ #include <memory> #include "base/process/process_metrics.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" #include "test/multiprocess.h" From cc60f9329e543355c2caf19cfbc0690a965ae6ad Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 20 Dec 2018 20:44:15 -0800 Subject: [PATCH 105/401] Refactor PEImageAnnotationsReader test In preparation for deleting the PEImageAnnotationsReader (and replacing it with the generic ImageAnnotationsReader) change the PEImageAnnotationsReader test to be a ModuleSnapshotWin test instead. The tests are still useful for testing the annotations on the module snapshot. Bug: crashpad:270 Change-Id: Ibbbc69c72ca2eb98bfae9dc9b57bf28e9d3f12e2 Reviewed-on: https://chromium-review.googlesource.com/c/1388018 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- snapshot/BUILD.gn | 2 +- snapshot/snapshot_test.gyp | 2 +- ...er_test.cc => module_snapshot_win_test.cc} | 23 ++++++++----------- 3 files changed, 11 insertions(+), 16 deletions(-) rename snapshot/win/{pe_image_annotations_reader_test.cc => module_snapshot_win_test.cc} (88%) diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 9fe8582a..b31c18af 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -371,7 +371,7 @@ source_set("snapshot_test") { "win/cpu_context_win_test.cc", "win/exception_snapshot_win_test.cc", "win/extra_memory_ranges_test.cc", - "win/pe_image_annotations_reader_test.cc", + "win/module_snapshot_win_test.cc", "win/pe_image_reader_test.cc", "win/process_reader_win_test.cc", "win/process_snapshot_win_test.cc", diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index b795d92f..396be345 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -96,7 +96,7 @@ 'win/cpu_context_win_test.cc', 'win/exception_snapshot_win_test.cc', 'win/extra_memory_ranges_test.cc', - 'win/pe_image_annotations_reader_test.cc', + 'win/module_snapshot_win_test.cc', 'win/pe_image_reader_test.cc', 'win/process_reader_win_test.cc', 'win/process_snapshot_win_test.cc', diff --git a/snapshot/win/pe_image_annotations_reader_test.cc b/snapshot/win/module_snapshot_win_test.cc similarity index 88% rename from snapshot/win/pe_image_annotations_reader_test.cc rename to snapshot/win/module_snapshot_win_test.cc index e1026008..6a14cf5e 100644 --- a/snapshot/win/pe_image_annotations_reader_test.cc +++ b/snapshot/win/module_snapshot_win_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "snapshot/win/pe_image_annotations_reader.h" +#include "snapshot/win/module_snapshot_win.h" #include <stdlib.h> #include <string.h> @@ -74,20 +74,15 @@ void TestAnnotationsOnCrash(TestType type, std::map<std::string, std::string> all_annotations_simple_map; std::vector<AnnotationSnapshot> all_annotation_objects; for (const ProcessInfo::Module& module : modules) { - PEImageReader pe_image_reader; - pe_image_reader.Initialize(&process_reader, - module.dll_base, - module.size, - base::UTF16ToUTF8(module.name)); - PEImageAnnotationsReader module_annotations_reader( - &process_reader, &pe_image_reader, module.name); + internal::ModuleSnapshotWin module_snapshot; + module_snapshot.Initialize(&process_reader, module); std::map<std::string, std::string> module_annotations_simple_map = - module_annotations_reader.SimpleMap(); + module_snapshot.AnnotationsSimpleMap(); all_annotations_simple_map.insert(module_annotations_simple_map.begin(), module_annotations_simple_map.end()); - auto module_annotations_list = module_annotations_reader.AnnotationsList(); + auto module_annotations_list = module_snapshot.AnnotationObjects(); all_annotation_objects.insert(all_annotation_objects.end(), module_annotations_list.begin(), module_annotations_list.end()); @@ -146,16 +141,16 @@ void TestAnnotationsOnCrash(TestType type, EXPECT_EQ(child.WaitForExit(), expected_exit_code); } -TEST(PEImageAnnotationsReader, DontCrash) { +TEST(ModuleSnapshotWinTest, DontCrash) { TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::kDefault); } -TEST(PEImageAnnotationsReader, CrashDebugBreak) { +TEST(ModuleSnapshotWinTest, CrashDebugBreak) { TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::kDefault); } #if defined(ARCH_CPU_64_BITS) -TEST(PEImageAnnotationsReader, DontCrashWOW64) { +TEST(ModuleSnapshotWinTest, DontCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } @@ -163,7 +158,7 @@ TEST(PEImageAnnotationsReader, DontCrashWOW64) { TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::k32Bit); } -TEST(PEImageAnnotationsReader, CrashDebugBreakWOW64) { +TEST(ModuleSnapshotWinTest, CrashDebugBreakWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } From 760da9b96abf10c529bb973481fca5e707088c09 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Fri, 21 Dec 2018 07:51:17 -0800 Subject: [PATCH 106/401] Delete snapshot/api/module_annotations_win* This API was added for Kasko several years ago but that project is defunct and this API does not appear to be used elsewhere. Bug: crashpad:270 Change-Id: I5a409deff7c5cf4f9f552893d4a49303f3000164 Reviewed-on: https://chromium-review.googlesource.com/c/1388022 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- snapshot/BUILD.gn | 25 ------- snapshot/api/module_annotations_win.cc | 54 -------------- snapshot/api/module_annotations_win.h | 42 ----------- snapshot/api/module_annotations_win_test.cc | 83 --------------------- snapshot/snapshot.gyp | 27 ------- snapshot/snapshot_test.gyp | 2 - 6 files changed, 233 deletions(-) delete mode 100644 snapshot/api/module_annotations_win.cc delete mode 100644 snapshot/api/module_annotations_win.h delete mode 100644 snapshot/api/module_annotations_win_test.cc diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index b31c18af..8d331fc0 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -235,29 +235,6 @@ static_library("snapshot") { } } -if (crashpad_is_win) { - static_library("snapshot_api") { - sources = [ - "api/module_annotations_win.cc", - "api/module_annotations_win.h", - ] - - public_configs = [ "..:crashpad_config" ] - - cflags = [ "/wd4201" ] - - deps = [ - ":snapshot", - "../compat", - "../third_party/mini_chromium:base", - "../util", - ] - } -} else { - group("snapshot_api") { - } -} - fuzzer_test("elf_image_reader_fuzzer") { sources = [ "elf/elf_image_reader_fuzzer.cc", @@ -367,7 +344,6 @@ source_set("snapshot_test") { if (crashpad_is_win) { sources += [ - "api/module_annotations_win_test.cc", "win/cpu_context_win_test.cc", "win/exception_snapshot_win_test.cc", "win/extra_memory_ranges_test.cc", @@ -399,7 +375,6 @@ source_set("snapshot_test") { public_configs = [ ":snapshot_test_link" ] deps = [ - ":snapshot_api", ":test_support", "../client", "../compat", diff --git a/snapshot/api/module_annotations_win.cc b/snapshot/api/module_annotations_win.cc deleted file mode 100644 index fd468703..00000000 --- a/snapshot/api/module_annotations_win.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2016 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/api/module_annotations_win.h" - -#include "snapshot/win/pe_image_annotations_reader.h" -#include "snapshot/win/pe_image_reader.h" -#include "snapshot/win/process_reader_win.h" -#include "util/misc/from_pointer_cast.h" -#include "util/win/get_module_information.h" - -namespace crashpad { - -bool ReadModuleAnnotations(HANDLE process, - HMODULE module, - std::map<std::string, std::string>* annotations) { - ProcessReaderWin process_reader; - if (!process_reader.Initialize(process, ProcessSuspensionState::kRunning)) - return false; - - MODULEINFO module_info; - if (!CrashpadGetModuleInformation( - process, module, &module_info, sizeof(module_info))) { - PLOG(ERROR) << "CrashpadGetModuleInformation"; - return false; - } - - PEImageReader image_reader; - if (!image_reader.Initialize( - &process_reader, - FromPointerCast<WinVMAddress>(module_info.lpBaseOfDll), - module_info.SizeOfImage, - "")) - return false; - - PEImageAnnotationsReader annotations_reader( - &process_reader, &image_reader, L""); - - *annotations = annotations_reader.SimpleMap(); - return true; -} - -} // namespace crashpad diff --git a/snapshot/api/module_annotations_win.h b/snapshot/api/module_annotations_win.h deleted file mode 100644 index e0240310..00000000 --- a/snapshot/api/module_annotations_win.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2016 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_API_MODULE_ANNOTATIONS_WIN_H_ -#define CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_ - -#include <windows.h> - -#include <map> -#include <string> - -namespace crashpad { - -//! \brief Reads the module annotations from another process. -//! -//! \param[in] process The handle to the process that hosts the \a module. -//! Requires PROCESS_QUERY_INFORMATION and PROCESS_VM_READ accesses. -//! \param[in] module The handle to the module from which the \a annotations -//! will be read. This module should be loaded in the target process. -//! \param[out] annotations The map that will be filled with the annotations. -//! Remains unchanged if the function returns 'false'. -//! -//! \return `true` if the annotations could be read succesfully, even if the -//! module doesn't contain any annotations. -bool ReadModuleAnnotations(HANDLE process, - HMODULE module, - std::map<std::string, std::string>* annotations); - -} // namespace crashpad - -#endif // CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_ diff --git a/snapshot/api/module_annotations_win_test.cc b/snapshot/api/module_annotations_win_test.cc deleted file mode 100644 index ecfa4659..00000000 --- a/snapshot/api/module_annotations_win_test.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2016 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/api/module_annotations_win.h" - -#include "client/crashpad_info.h" -#include "gtest/gtest.h" -#include "test/win/win_multiprocess.h" -#include "util/file/file_io.h" - -namespace crashpad { -namespace test { -namespace { - -class ModuleAnnotationsMultiprocessTest final : public WinMultiprocess { - private: - void WinMultiprocessParent() override { - // Read the child executable module. - HMODULE module = nullptr; - CheckedReadFileExactly(ReadPipeHandle(), &module, sizeof(module)); - - // Reopen the child process with necessary access. - HANDLE process_handle = - OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - FALSE, - GetProcessId(ChildProcess())); - EXPECT_TRUE(process_handle); - - // Read the module annotations in the child process and verify them. - std::map<std::string, std::string> annotations; - ASSERT_TRUE(ReadModuleAnnotations(process_handle, module, &annotations)); - - EXPECT_GE(annotations.size(), 3u); - EXPECT_EQ(annotations["#APITEST# key"], "value"); - EXPECT_EQ(annotations["#APITEST# x"], "y"); - EXPECT_EQ(annotations["#APITEST# empty_value"], ""); - - // Signal the child process to terminate. - char c = ' '; - CheckedWriteFile(WritePipeHandle(), &c, sizeof(c)); - } - - void WinMultiprocessChild() override { - // Set some test annotations. - crashpad::CrashpadInfo* crashpad_info = - crashpad::CrashpadInfo::GetCrashpadInfo(); - - crashpad::SimpleStringDictionary* simple_annotations = - new crashpad::SimpleStringDictionary(); - simple_annotations->SetKeyValue("#APITEST# key", "value"); - simple_annotations->SetKeyValue("#APITEST# x", "y"); - simple_annotations->SetKeyValue("#APITEST# empty_value", ""); - - crashpad_info->set_simple_annotations(simple_annotations); - - // Send the executable module. - HMODULE module = GetModuleHandle(nullptr); - CheckedWriteFile(WritePipeHandle(), &module, sizeof(module)); - - // Wait until a signal from the parent process to terminate. - char c; - CheckedReadFileExactly(ReadPipeHandle(), &c, sizeof(c)); - } -}; - -TEST(ModuleAnnotationsWin, ReadAnnotations) { - WinMultiprocess::Run<ModuleAnnotationsMultiprocessTest>(); -} - -} // namespace -} // namespace test -} // namespace crashpad diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index ac7de298..8c563f52 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -210,32 +210,5 @@ }], ], }, - { - 'variables': { - 'conditions': [ - ['OS == "win"', { - 'snapshot_api_target_type%': 'static_library', - }, { - # There are no source files except on Windows. - 'snapshot_api_target_type%': 'none', - }], - ], - }, - 'target_name': 'crashpad_snapshot_api', - 'type': '<(snapshot_api_target_type)', - 'dependencies': [ - 'crashpad_snapshot', - '../compat/compat.gyp:crashpad_compat', - '../third_party/mini_chromium/mini_chromium.gyp:base', - '../util/util.gyp:crashpad_util', - ], - 'include_dirs': [ - '..', - ], - 'sources': [ - 'api/module_annotations_win.cc', - 'api/module_annotations_win.h', - ], - }, ], } diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index 396be345..cf7b8aec 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -57,7 +57,6 @@ 'crashpad_snapshot_test_module_large', 'crashpad_snapshot_test_module_small', 'snapshot.gyp:crashpad_snapshot', - 'snapshot.gyp:crashpad_snapshot_api', '../client/client.gyp:crashpad_client', '../compat/compat.gyp:crashpad_compat', '../test/test.gyp:crashpad_gtest_main', @@ -70,7 +69,6 @@ '..', ], 'sources': [ - 'api/module_annotations_win_test.cc', 'cpu_context_test.cc', 'memory_snapshot_test.cc', 'crashpad_info_client_options_test.cc', From 60ff012872556b2a8ef68422071976c24a5075c3 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Fri, 21 Dec 2018 13:06:12 -0800 Subject: [PATCH 107/401] Change ProcessMemory to accept VMSizes As Mark noted in [1] ProcessMemory should accept VMSize instead of size_t, the two types can differ on platforms where a cross-bitness handler could cause a 32-bit handler to inspect a 64-bit process. By centralizing the checks in ProcessMemory, we can leave the individual platform-specific implementations (in ProcessMemory*::ReadUpTo) to accept size_ts. [1] crrev.com/c/1388017/2/snapshot/crashpad_types/crashpad_info_reader.cc#70 Bug: crashpad:270 Change-Id: I3aab483221de36f3b1478cb9503101b142dae681 Reviewed-on: https://chromium-review.googlesource.com/c/1387756 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- util/process/process_memory.cc | 31 ++++++++++++++++++++++--------- util/process/process_memory.h | 6 +++--- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/util/process/process_memory.cc b/util/process/process_memory.cc index c23af93e..ab87b940 100644 --- a/util/process/process_memory.cc +++ b/util/process/process_memory.cc @@ -17,13 +17,20 @@ #include <algorithm> #include "base/logging.h" +#include "util/numeric/safe_assignment.h" namespace crashpad { -bool ProcessMemory::Read(VMAddress address, size_t size, void* buffer) const { +bool ProcessMemory::Read(VMAddress address, VMSize size, void* buffer) const { + size_t local_size; + if (!AssignIfInRange(&local_size, size)) { + LOG(ERROR) << "size " << size << " out of bounds for size_t"; + return false; + } + char* buffer_c = static_cast<char*>(buffer); - while (size > 0) { - ssize_t bytes_read = ReadUpTo(address, size, buffer_c); + while (local_size > 0) { + ssize_t bytes_read = ReadUpTo(address, local_size, buffer_c); if (bytes_read < 0) { return false; } @@ -31,8 +38,8 @@ bool ProcessMemory::Read(VMAddress address, size_t size, void* buffer) const { LOG(ERROR) << "short read"; return false; } - DCHECK_LE(static_cast<size_t>(bytes_read), size); - size -= bytes_read; + DCHECK_LE(static_cast<size_t>(bytes_read), local_size); + local_size -= bytes_read; address += bytes_read; buffer_c += bytes_read; } @@ -41,15 +48,21 @@ bool ProcessMemory::Read(VMAddress address, size_t size, void* buffer) const { bool ProcessMemory::ReadCStringInternal(VMAddress address, bool has_size, - size_t size, + VMSize size, std::string* string) const { + size_t local_size; + if (!AssignIfInRange(&local_size, size)) { + LOG(ERROR) << "size " << size << " out of bounds for size_t"; + return false; + } + string->clear(); char buffer[4096]; do { size_t read_size; if (has_size) { - read_size = std::min(sizeof(buffer), size); + read_size = std::min(sizeof(buffer), local_size); } else { read_size = sizeof(buffer); } @@ -70,8 +83,8 @@ bool ProcessMemory::ReadCStringInternal(VMAddress address, string->append(buffer, bytes_read); address += bytes_read; - size -= bytes_read; - } while (!has_size || size > 0); + local_size -= bytes_read; + } while (!has_size || local_size > 0); LOG(ERROR) << "unterminated string"; return false; diff --git a/util/process/process_memory.h b/util/process/process_memory.h index 5ea595ef..32e7472f 100644 --- a/util/process/process_memory.h +++ b/util/process/process_memory.h @@ -46,7 +46,7 @@ class ProcessMemory { //! //! \return `true` on success, with \a buffer filled appropriately. `false` on //! failure, with a message logged. - bool Read(VMAddress address, size_t size, void* buffer) const; + bool Read(VMAddress address, VMSize size, void* buffer) const; //! \brief Reads a `NUL`-terminated C string from the target process into a //! string in the current process. @@ -79,7 +79,7 @@ class ProcessMemory { //! a `NUL` terminator is not found within \a size bytes, or when //! encountering unmapped or unreadable pages. bool ReadCStringSizeLimited(VMAddress address, - size_t size, + VMSize size, std::string* string) const { return ReadCStringInternal(address, true, size, string); } @@ -124,7 +124,7 @@ class ProcessMemory { //! encountering unmapped or unreadable pages. virtual bool ReadCStringInternal(VMAddress address, bool has_size, - size_t size, + VMSize size, std::string* string) const; }; From bcce07414385fec1570c10ac7c7312a7f5dcb373 Mon Sep 17 00:00:00 2001 From: David Bienvenu <davidbienvenu@chromium.org> Date: Wed, 2 Jan 2019 15:36:06 -0800 Subject: [PATCH 108/401] Make crashpad support either PSAPI_VERSION 1 or 2 Bug: 584969 Change-Id: I03913e8987a576154b29cac18e95c14d121c9762 Reviewed-on: https://chromium-review.googlesource.com/c/1393605 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- snapshot/win/pe_image_reader_test.cc | 4 +++- util/win/get_module_information.cc | 6 +++++- util/win/get_module_information.h | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/snapshot/win/pe_image_reader_test.cc b/snapshot/win/pe_image_reader_test.cc index ac456e2d..161d9c8e 100644 --- a/snapshot/win/pe_image_reader_test.cc +++ b/snapshot/win/pe_image_reader_test.cc @@ -14,7 +14,9 @@ #include "snapshot/win/pe_image_reader.h" -#define PSAPI_VERSION 1 +#ifndef PSAPI_VERSION +#define PSAPI_VERSION 2 +#endif #include <psapi.h> #include "base/files/file_path.h" diff --git a/util/win/get_module_information.cc b/util/win/get_module_information.cc index 1a9fd0c4..850bfe12 100644 --- a/util/win/get_module_information.cc +++ b/util/win/get_module_information.cc @@ -22,9 +22,13 @@ BOOL CrashpadGetModuleInformation(HANDLE process, HMODULE module, MODULEINFO* module_info, DWORD cb) { +#if PSAPI_VERSION == 1 static const auto get_module_information = - GET_FUNCTION_REQUIRED(L"psapi.dll", GetModuleInformation); + GET_FUNCTION_REQUIRED(L"psapi.dll", GetModuleInformation); return get_module_information(process, module, module_info, cb); +#elif PSAPI_VERSION == 2 + return GetModuleInformation(process, module, module_info, cb); +#endif } } // namespace crashpad diff --git a/util/win/get_module_information.h b/util/win/get_module_information.h index c7d1cf17..8fce0350 100644 --- a/util/win/get_module_information.h +++ b/util/win/get_module_information.h @@ -17,7 +17,9 @@ #include <windows.h> -#define PSAPI_VERSION 1 +#ifndef PSAPI_VERSION +#define PSAPI_VERSION 2 +#endif #include <psapi.h> namespace crashpad { From 8f5d83b9e3cdaae51da1ea940e658e6615a68497 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Fri, 21 Dec 2018 14:07:06 -0800 Subject: [PATCH 109/401] Change ProcessMemoryRange to use VMSize Follow up to https://crrev.com/c/1387756 replace size_t with VMSize. Bug: crashpad:270 Change-Id: I22ac9e3503ef3e9707b2ad0758ae133c5a746f27 Reviewed-on: https://chromium-review.googlesource.com/c/1389235 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- util/process/process_memory_range.cc | 6 +++--- util/process/process_memory_range.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/util/process/process_memory_range.cc b/util/process/process_memory_range.cc index aee8c808..caa4315f 100644 --- a/util/process/process_memory_range.cc +++ b/util/process/process_memory_range.cc @@ -67,7 +67,7 @@ bool ProcessMemoryRange::RestrictRange(VMAddress base, VMSize size) { } bool ProcessMemoryRange::Read(VMAddress address, - size_t size, + VMSize size, void* buffer) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); CheckedVMAddressRange read_range(range_.Is64Bit(), address, size); @@ -79,14 +79,14 @@ bool ProcessMemoryRange::Read(VMAddress address, } bool ProcessMemoryRange::ReadCStringSizeLimited(VMAddress address, - size_t size, + VMSize size, std::string* string) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); if (!range_.ContainsValue(address)) { LOG(ERROR) << "read out of range"; return false; } - size = std::min(size, base::checked_cast<size_t>(range_.End() - address)); + size = std::min(size, range_.End() - address); return memory_->ReadCStringSizeLimited(address, size, string); } diff --git a/util/process/process_memory_range.h b/util/process/process_memory_range.h index 2b654ba1..aabee498 100644 --- a/util/process/process_memory_range.h +++ b/util/process/process_memory_range.h @@ -97,7 +97,7 @@ class ProcessMemoryRange { //! //! \return `true` on success, with \a buffer filled appropriately. `false` on //! failure, with a message logged. - bool Read(VMAddress address, size_t size, void* buffer) const; + bool Read(VMAddress address, VMSize size, void* buffer) const; //! \brief Reads a `NUL`-terminated C string from the target process into a //! string in the current process. @@ -113,7 +113,7 @@ class ProcessMemoryRange { //! a `NUL` terminator is not found within \a size bytes, or when //! encountering unmapped or unreadable pages. bool ReadCStringSizeLimited(VMAddress address, - size_t size, + VMSize size, std::string* string) const; private: From c8a016b99d97e2e5642fd7892b48a5ed0eb6d0d1 Mon Sep 17 00:00:00 2001 From: Avi Drissman <avi@chromium.org> Date: Thu, 3 Jan 2019 13:36:02 -0500 Subject: [PATCH 110/401] Remove base's arraysize from Crashpad. BUG=837308 R=mark@chromium.org Change-Id: Ibecbfc7bc2d61ee54bc1114e4b20978adbc77db2 Reviewed-on: https://chromium-review.googlesource.com/c/1393921 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Avi Drissman <avi@chromium.org> --- client/crash_report_database_mac.mm | 3 +- client/crashpad_client_win_test.cc | 1 - client/simulate_crash_mac.cc | 6 +- client/simulate_crash_mac_test.cc | 10 ++- handler/mac/file_limit_annotation.cc | 4 +- handler/win/crashy_test_program.cc | 6 +- handler/win/hanging_program.cc | 6 +- minidump/minidump_annotation_writer_test.cc | 4 +- minidump/minidump_byte_array_writer_test.cc | 5 +- minidump/minidump_exception_writer.cc | 4 +- minidump/minidump_exception_writer_test.cc | 3 +- minidump/minidump_file_writer_test.cc | 3 +- minidump/minidump_memory_writer_test.cc | 8 +-- minidump/minidump_misc_info_writer.cc | 12 ++-- minidump/minidump_misc_info_writer_test.cc | 53 +++++++------- ...nidump_module_crashpad_info_writer_test.cc | 7 +- minidump/minidump_module_writer_test.cc | 11 +-- minidump/minidump_rva_list_writer_test.cc | 5 +- minidump/minidump_string_writer_test.cc | 9 +-- minidump/minidump_system_info_writer.cc | 11 ++- minidump/minidump_thread_id_map_test.cc | 5 +- minidump/minidump_thread_writer_test.cc | 11 +-- minidump/minidump_writable.cc | 3 +- minidump/test/minidump_context_test_util.cc | 72 +++++++++---------- snapshot/capture_memory.cc | 7 +- snapshot/cpu_context.cc | 10 +-- snapshot/cpu_context_test.cc | 22 +++--- .../memory_map_region_snapshot_fuchsia.cc | 3 +- .../fuchsia/process_reader_fuchsia_test.cc | 3 +- .../fuchsia/process_snapshot_fuchsia_test.cc | 7 +- .../linux/exception_snapshot_linux_test.cc | 11 +-- snapshot/linux/process_reader_linux_test.cc | 3 +- snapshot/mac/mach_o_image_reader.cc | 6 +- .../mac/mach_o_image_segment_reader_test.cc | 8 +-- snapshot/mac/process_reader_mac_test.cc | 7 +- snapshot/mac/process_types.cc | 4 +- snapshot/mac/process_types/custom.cc | 5 +- snapshot/mac/process_types_test.cc | 10 ++- .../process_snapshot_minidump_test.cc | 25 ++++--- snapshot/minidump/thread_snapshot_minidump.cc | 17 ++--- snapshot/posix/timezone.cc | 4 +- snapshot/posix/timezone_test.cc | 3 +- .../sanitization_information_test.cc | 5 +- snapshot/test/test_cpu_context.cc | 32 ++++----- snapshot/win/cpu_context_win_test.cc | 10 +-- .../crashpad_snapshot_test_image_reader.cc | 7 +- snapshot/win/pe_image_annotations_reader.cc | 3 +- snapshot/win/pe_image_reader.cc | 3 +- snapshot/win/process_reader_win_test.cc | 5 +- snapshot/win/process_snapshot_win.cc | 7 +- test/hex_string.h | 4 +- test/hex_string_test.cc | 4 +- tools/crashpad_database_util.cc | 10 +-- util/BUILD.gn | 4 +- util/file/delimited_file_reader.cc | 3 +- util/file/delimited_file_reader_test.cc | 7 +- util/file/file_io_test.cc | 3 +- util/linux/direct_ptrace_connection.cc | 3 +- util/linux/proc_stat_reader.cc | 3 +- util/linux/ptrace_client.cc | 3 +- util/mac/checked_mach_address_range_test.cc | 8 +-- util/mac/launchd_test.mm | 10 +-- util/mac/xattr.cc | 1 - util/mach/child_port_handshake.cc | 3 +- util/mach/child_port_server.cc | 3 +- .../composite_mach_message_server_test.cc | 13 ++-- util/mach/exc_client_variants_test.cc | 9 +-- util/mach/exc_server_variants.cc | 7 +- util/mach/exc_server_variants_test.cc | 39 +++++----- util/mach/exception_behaviors_test.cc | 4 +- util/mach/exception_types_test.cc | 8 +-- util/mach/mach_message_server_test.cc | 3 +- util/mach/mach_message_test.cc | 1 + util/mach/notify_server.cc | 3 +- util/mach/symbolic_constants_mach.cc | 28 ++++---- util/mach/symbolic_constants_mach_test.cc | 57 +++++++-------- util/misc/arraysize.h | 39 ++++++++++ ...ysize_unsafe_test.cc => arraysize_test.cc} | 24 +++---- util/misc/arraysize_unsafe.h | 27 ------- util/misc/capture_context_test_util_win.cc | 8 +-- util/misc/clock_test.cc | 4 +- util/misc/paths_win.cc | 7 +- util/misc/random_string_test.cc | 6 +- util/misc/uuid_test.cc | 10 +-- util/net/http_transport_socket.cc | 3 +- 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 | 3 +- util/posix/close_stdio.cc | 1 + util/posix/process_info_mac.cc | 9 +-- util/posix/scoped_mmap_test.cc | 11 +-- util/posix/signals.cc | 11 +-- util/posix/signals_test.cc | 3 +- util/posix/symbolic_constants_posix.cc | 11 ++- util/posix/symbolic_constants_posix_test.cc | 16 ++--- util/process/process_memory_range_test.cc | 15 ++-- util/stdlib/string_number_conversion_test.cc | 14 ++-- util/stdlib/strlcpy_test.cc | 14 ++-- util/stdlib/thread_safe_vector_test.cc | 9 +-- util/synchronization/semaphore_test.cc | 6 +- util/thread/thread_log_messages_test.cc | 7 +- util/thread/thread_test.cc | 1 - util/util.gyp | 2 +- util/util_test.gyp | 2 +- util/win/command_line_test.cc | 16 ++--- util/win/exception_handler_server.cc | 5 +- util/win/ntstatus_logging.cc | 3 +- util/win/registration_protocol_win.cc | 9 +-- util/win/safe_terminate_process_test.cc | 3 +- 110 files changed, 550 insertions(+), 504 deletions(-) create mode 100644 util/misc/arraysize.h rename util/misc/{arraysize_unsafe_test.cc => arraysize_test.cc} (68%) delete mode 100644 util/misc/arraysize_unsafe.h diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 3106dc2c..0980fe3f 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -35,6 +35,7 @@ #include "client/settings.h" #include "util/file/file_io.h" #include "util/mac/xattr.h" +#include "util/misc/arraysize.h" #include "util/misc/initialization_state_dcheck.h" #include "util/misc/metrics.h" @@ -279,7 +280,7 @@ bool CrashReportDatabaseMac::Initialize(bool may_create) { } // Create the three processing directories for the database. - for (size_t i = 0; i < arraysize(kReportDirectories); ++i) { + for (size_t i = 0; i < ArraySize(kReportDirectories); ++i) { if (!CreateOrEnsureDirectoryExists(base_dir_.Append(kReportDirectories[i]))) return false; } diff --git a/client/crashpad_client_win_test.cc b/client/crashpad_client_win_test.cc index 99778baa..b950699a 100644 --- a/client/crashpad_client_win_test.cc +++ b/client/crashpad_client_win_test.cc @@ -17,7 +17,6 @@ #include <vector> #include "base/files/file_path.h" -#include "base/macros.h" #include "base/logging.h" #include "gtest/gtest.h" #include "test/test_paths.h" diff --git a/client/simulate_crash_mac.cc b/client/simulate_crash_mac.cc index 1e2d8e42..1f7eca9e 100644 --- a/client/simulate_crash_mac.cc +++ b/client/simulate_crash_mac.cc @@ -20,13 +20,13 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/mac/scoped_mach_port.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "util/mach/exc_client_variants.h" #include "util/mach/exception_behaviors.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -191,7 +191,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 = arraysize(codes); + mach_msg_type_number_t code_count = ArraySize(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 @@ -213,7 +213,7 @@ void SimulateCrash(const NativeCPUContext& cpu_context) { bool success = false; for (size_t target_type_index = 0; - !success && target_type_index < arraysize(kTargetTypes); + !success && target_type_index < ArraySize(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 1d63ff65..910971ae 100644 --- a/client/simulate_crash_mac_test.cc +++ b/client/simulate_crash_mac_test.cc @@ -31,6 +31,7 @@ #include "util/mach/mach_message.h" #include "util/mach/mach_message_server.h" #include "util/mach/symbolic_constants_mach.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -342,15 +343,13 @@ TEST(SimulateCrash, SimulateCrash) { #endif }; - for (size_t target_index = 0; - target_index < arraysize(kTargets); + for (size_t target_index = 0; target_index < ArraySize(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 < arraysize(kBehaviors); + for (size_t behavior_index = 0; behavior_index < ArraySize(kBehaviors); ++behavior_index) { exception_behavior_t behavior = kBehaviors[behavior_index]; SCOPED_TRACE(base::StringPrintf( @@ -364,8 +363,7 @@ TEST(SimulateCrash, SimulateCrash) { target, behavior, THREAD_STATE_NONE); test_simulate_crash_mac.Run(); } else { - for (size_t flavor_index = 0; - flavor_index < arraysize(kFlavors); + for (size_t flavor_index = 0; flavor_index < ArraySize(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 cf56eb86..5646bdea 100644 --- a/handler/mac/file_limit_annotation.cc +++ b/handler/mac/file_limit_annotation.cc @@ -24,10 +24,10 @@ #include <string> #include "base/format_macros.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" #include "client/simple_string_dictionary.h" +#include "util/misc/arraysize.h" #include "util/posix/scoped_dir.h" namespace crashpad { @@ -108,7 +108,7 @@ void RecordFileLimitAnnotation() { int mib[] = {CTL_KERN, KERN_MAXFILES}; size = sizeof(value); std::string max_files = FormatFromSysctl( - sysctl(mib, arraysize(mib), &value, &size, nullptr, 0), &value, &size); + sysctl(mib, ArraySize(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 a4f4797b..d6b4dead 100644 --- a/handler/win/crashy_test_program.cc +++ b/handler/win/crashy_test_program.cc @@ -26,10 +26,10 @@ #include "base/files/file_path.h" #include "base/logging.h" -#include "base/macros.h" #include "build/build_config.h" #include "client/crashpad_client.h" #include "client/crashpad_info.h" +#include "util/misc/arraysize.h" #include "util/win/critical_section_with_debug_info.h" #include "util/win/get_function.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, arraysize(kPageTypes) * kPageSize, MEM_RESERVE, PAGE_READWRITE); + nullptr, ArraySize(kPageTypes) * kPageSize, MEM_RESERVE, PAGE_READWRITE); PCHECK(reserve) << "VirtualAlloc MEM_RESERVE"; uintptr_t reserve_as_int = reinterpret_cast<uintptr_t>(reserve); - for (size_t i = 0; i < arraysize(kPageTypes); ++i) { + for (size_t i = 0; i < ArraySize(kPageTypes); ++i) { void* result = VirtualAlloc(reinterpret_cast<void*>(reserve_as_int + (kPageSize * i)), kPageSize, diff --git a/handler/win/hanging_program.cc b/handler/win/hanging_program.cc index 840c5125..49d5cea4 100644 --- a/handler/win/hanging_program.cc +++ b/handler/win/hanging_program.cc @@ -17,11 +17,11 @@ #include "base/debug/alias.h" #include "base/logging.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "client/crashpad_client.h" #include "client/crashpad_info.h" +#include "util/misc/arraysize.h" namespace { @@ -123,8 +123,8 @@ int wmain(int argc, wchar_t* argv[]) { fflush(stdout); // This is not expected to return. - DWORD count = - WaitForMultipleObjects(arraysize(threads), threads, true, INFINITE); + DWORD count = WaitForMultipleObjects( + static_cast<DWORD>(ArraySize(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 1641d1d6..f86ff467 100644 --- a/minidump/minidump_annotation_writer_test.cc +++ b/minidump/minidump_annotation_writer_test.cc @@ -16,13 +16,13 @@ #include <memory> -#include "base/macros.h" #include "gtest/gtest.h" #include "minidump/minidump_extensions.h" #include "minidump/test/minidump_byte_array_writer_test_util.h" #include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -107,7 +107,7 @@ TEST(MinidumpAnnotationWriter, ThreeItems) { MinidumpAnnotationListWriter list_writer; - for (size_t i = 0; i < arraysize(kNames); ++i) { + for (size_t i = 0; i < ArraySize(kNames); ++i) { auto annotation = std::make_unique<MinidumpAnnotationWriter>(); 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 f20ad35a..94fad5c6 100644 --- a/minidump/minidump_byte_array_writer_test.cc +++ b/minidump/minidump_byte_array_writer_test.cc @@ -21,6 +21,7 @@ #include "gtest/gtest.h" #include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -34,7 +35,7 @@ TEST(MinidumpByteArrayWriter, Write) { {}, }; - for (size_t i = 0; i < arraysize(kTests); ++i) { + for (size_t i = 0; i < ArraySize(kTests); ++i) { SCOPED_TRACE(base::StringPrintf("index %" PRIuS, i)); StringFile string_file; @@ -66,7 +67,7 @@ TEST(MinidumpByteArrayWriter, SetData) { {}, }; - for (size_t i = 0; i < arraysize(kTests); ++i) { + for (size_t i = 0; i < ArraySize(kTests); ++i) { SCOPED_TRACE(base::StringPrintf("index %" PRIuS, i)); crashpad::MinidumpByteArrayWriter writer; diff --git a/minidump/minidump_exception_writer.cc b/minidump/minidump_exception_writer.cc index d870de36..b0e1e627 100644 --- a/minidump/minidump_exception_writer.cc +++ b/minidump/minidump_exception_writer.cc @@ -21,7 +21,7 @@ #include "minidump/minidump_context_writer.h" #include "snapshot/exception_snapshot.h" #include "util/file/file_writer.h" -#include "util/misc/arraysize_unsafe.h" +#include "util/misc/arraysize.h" namespace crashpad { @@ -65,7 +65,7 @@ void MinidumpExceptionWriter::SetExceptionInformation( const size_t parameters = exception_information.size(); constexpr size_t kMaxParameters = - ARRAYSIZE_UNSAFE(exception_.ExceptionRecord.ExceptionInformation); + ArraySize(exception_.ExceptionRecord.ExceptionInformation); CHECK_LE(parameters, kMaxParameters); exception_.ExceptionRecord.NumberParameters = diff --git a/minidump/minidump_exception_writer_test.cc b/minidump/minidump_exception_writer_test.cc index e4dc5faa..b3a4e809 100644 --- a/minidump/minidump_exception_writer_test.cc +++ b/minidump/minidump_exception_writer_test.cc @@ -29,6 +29,7 @@ #include "snapshot/test/test_exception_snapshot.h" #include "test/gtest_death.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -80,7 +81,7 @@ void ExpectExceptionStream(const MINIDUMP_EXCEPTION_STREAM* expected, expected->ExceptionRecord.NumberParameters); EXPECT_EQ(observed->ExceptionRecord.__unusedAlignment, 0u); for (size_t index = 0; - index < arraysize(observed->ExceptionRecord.ExceptionInformation); + index < ArraySize(observed->ExceptionRecord.ExceptionInformation); ++index) { EXPECT_EQ(observed->ExceptionRecord.ExceptionInformation[index], expected->ExceptionRecord.ExceptionInformation[index]); diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index 067ef96b..ef4813ed 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -36,6 +36,7 @@ #include "snapshot/test/test_thread_snapshot.h" #include "test/gtest_death.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -134,7 +135,7 @@ TEST(MinidumpFileWriter, AddUserExtensionStream) { minidump_file.SetTimestamp(kTimestamp); static constexpr uint8_t kStreamData[] = "Hello World!"; - constexpr size_t kStreamSize = arraysize(kStreamData); + constexpr size_t kStreamSize = ArraySize(kStreamData); constexpr MinidumpStreamType kStreamType = static_cast<MinidumpStreamType>(0x4d); diff --git a/minidump/minidump_memory_writer_test.cc b/minidump/minidump_memory_writer_test.cc index 60b7fa8a..fa71caf0 100644 --- a/minidump/minidump_memory_writer_test.cc +++ b/minidump/minidump_memory_writer_test.cc @@ -26,6 +26,7 @@ #include "minidump/test/minidump_writable_test_util.h" #include "snapshot/test/test_memory_snapshot.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -340,7 +341,7 @@ TEST(MinidumpMemoryWriter, ExtraMemory) { TEST(MinidumpMemoryWriter, AddFromSnapshot) { MINIDUMP_MEMORY_DESCRIPTOR expect_memory_descriptors[3] = {}; - uint8_t values[arraysize(expect_memory_descriptors)] = {}; + uint8_t values[ArraySize(expect_memory_descriptors)] = {}; expect_memory_descriptors[0].StartOfMemoryRange = 0; expect_memory_descriptors[0].Memory.DataSize = 0x1000; @@ -356,8 +357,7 @@ TEST(MinidumpMemoryWriter, AddFromSnapshot) { std::vector<std::unique_ptr<TestMemorySnapshot>> memory_snapshots_owner; std::vector<const MemorySnapshot*> memory_snapshots; - for (size_t index = 0; - index < arraysize(expect_memory_descriptors); + for (size_t index = 0; index < ArraySize(expect_memory_descriptors); ++index) { memory_snapshots_owner.push_back(std::make_unique<TestMemorySnapshot>()); TestMemorySnapshot* memory_snapshot = memory_snapshots_owner.back().get(); @@ -396,7 +396,7 @@ TEST(MinidumpMemoryWriter, AddFromSnapshot) { TEST(MinidumpMemoryWriter, CoalesceExplicitMultiple) { MINIDUMP_MEMORY_DESCRIPTOR expect_memory_descriptors[4] = {}; - uint8_t values[arraysize(expect_memory_descriptors)] = {}; + uint8_t values[ArraySize(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 d83ed237..2d70d00a 100644 --- a/minidump/minidump_misc_info_writer.cc +++ b/minidump/minidump_misc_info_writer.cc @@ -26,7 +26,7 @@ #include "snapshot/process_snapshot.h" #include "snapshot/system_snapshot.h" #include "util/file/file_writer.h" -#include "util/misc/arraysize_unsafe.h" +#include "util/misc/arraysize.h" #include "util/numeric/in_range_cast.h" #include "util/numeric/safe_assignment.h" @@ -302,7 +302,7 @@ void MinidumpMiscInfoWriter::SetTimeZone(uint32_t time_zone_id, internal::MinidumpWriterUtil::AssignUTF8ToUTF16( misc_info_.TimeZone.StandardName, - ARRAYSIZE_UNSAFE(misc_info_.TimeZone.StandardName), + ArraySize(misc_info_.TimeZone.StandardName), standard_name); misc_info_.TimeZone.StandardDate = standard_date; @@ -310,7 +310,7 @@ void MinidumpMiscInfoWriter::SetTimeZone(uint32_t time_zone_id, internal::MinidumpWriterUtil::AssignUTF8ToUTF16( misc_info_.TimeZone.DaylightName, - ARRAYSIZE_UNSAFE(misc_info_.TimeZone.DaylightName), + ArraySize(misc_info_.TimeZone.DaylightName), daylight_name); misc_info_.TimeZone.DaylightDate = daylight_date; @@ -327,12 +327,10 @@ void MinidumpMiscInfoWriter::SetBuildString( misc_info_.Flags1 |= MINIDUMP_MISC4_BUILDSTRING; internal::MinidumpWriterUtil::AssignUTF8ToUTF16( - misc_info_.BuildString, - ARRAYSIZE_UNSAFE(misc_info_.BuildString), - build_string); + misc_info_.BuildString, ArraySize(misc_info_.BuildString), build_string); internal::MinidumpWriterUtil::AssignUTF8ToUTF16( misc_info_.DbgBldStr, - ARRAYSIZE_UNSAFE(misc_info_.DbgBldStr), + ArraySize(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 3c60ebcc..e134ccd2 100644 --- a/minidump/minidump_misc_info_writer_test.cc +++ b/minidump/minidump_misc_info_writer_test.cc @@ -31,7 +31,7 @@ #include "snapshot/test/test_process_snapshot.h" #include "snapshot/test/test_system_snapshot.h" #include "util/file/string_file.h" -#include "util/misc/arraysize_unsafe.h" +#include "util/misc/arraysize.h" #include "util/stdlib/strlcpy.h" namespace crashpad { @@ -127,7 +127,7 @@ void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_3>( SCOPED_TRACE("Standard"); ExpectNULPaddedString16Equal(expected->TimeZone.StandardName, observed->TimeZone.StandardName, - arraysize(expected->TimeZone.StandardName)); + ArraySize(expected->TimeZone.StandardName)); ExpectSystemTimeEqual(&expected->TimeZone.StandardDate, &observed->TimeZone.StandardDate); EXPECT_EQ(observed->TimeZone.StandardBias, expected->TimeZone.StandardBias); @@ -136,7 +136,7 @@ void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_3>( SCOPED_TRACE("Daylight"); ExpectNULPaddedString16Equal(expected->TimeZone.DaylightName, observed->TimeZone.DaylightName, - arraysize(expected->TimeZone.DaylightName)); + ArraySize(expected->TimeZone.DaylightName)); ExpectSystemTimeEqual(&expected->TimeZone.DaylightDate, &observed->TimeZone.DaylightDate); EXPECT_EQ(observed->TimeZone.DaylightBias, expected->TimeZone.DaylightBias); @@ -154,13 +154,13 @@ void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_4>( SCOPED_TRACE("BuildString"); ExpectNULPaddedString16Equal(expected->BuildString, observed->BuildString, - arraysize(expected->BuildString)); + ArraySize(expected->BuildString)); } { SCOPED_TRACE("DbgBldStr"); ExpectNULPaddedString16Equal(expected->DbgBldStr, observed->DbgBldStr, - arraysize(expected->DbgBldStr)); + ArraySize(expected->DbgBldStr)); } } @@ -176,7 +176,7 @@ void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_5>( EXPECT_EQ(observed->XStateData.EnabledFeatures, expected->XStateData.EnabledFeatures); for (size_t feature_index = 0; - feature_index < arraysize(observed->XStateData.Features); + feature_index < ArraySize(observed->XStateData.Features); ++feature_index) { SCOPED_TRACE(base::StringPrintf("feature_index %" PRIuS, feature_index)); EXPECT_EQ(observed->XStateData.Features[feature_index].Offset, @@ -396,7 +396,7 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); c16lcpy(expected.TimeZone.StandardName, standard_name_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.TimeZone.StandardName)); + ArraySize(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kStandardDate, sizeof(expected.TimeZone.StandardDate)); @@ -404,7 +404,7 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); c16lcpy(expected.TimeZone.DaylightName, daylight_name_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.TimeZone.DaylightName)); + ArraySize(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kDaylightDate, sizeof(expected.TimeZone.DaylightDate)); @@ -424,10 +424,9 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { constexpr int32_t kBias = 300; MINIDUMP_MISC_INFO_N tmp; ALLOW_UNUSED_LOCAL(tmp); - std::string standard_name(ARRAYSIZE_UNSAFE(tmp.TimeZone.StandardName) + 1, - 's'); + std::string standard_name(ArraySize(tmp.TimeZone.StandardName) + 1, 's'); constexpr int32_t kStandardBias = 0; - std::string daylight_name(ARRAYSIZE_UNSAFE(tmp.TimeZone.DaylightName), 'd'); + std::string daylight_name(ArraySize(tmp.TimeZone.DaylightName), 'd'); constexpr int32_t kDaylightBias = -60; // Test using kSystemTimeZero, because not all platforms will be able to @@ -458,7 +457,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { base::string16 standard_name_utf16 = base::UTF8ToUTF16(standard_name); c16lcpy(expected.TimeZone.StandardName, standard_name_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.TimeZone.StandardName)); + ArraySize(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); @@ -466,7 +465,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { base::string16 daylight_name_utf16 = base::UTF8ToUTF16(daylight_name); c16lcpy(expected.TimeZone.DaylightName, daylight_name_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.TimeZone.DaylightName)); + ArraySize(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kSystemTimeZero, sizeof(expected.TimeZone.DaylightDate)); @@ -497,12 +496,12 @@ TEST(MinidumpMiscInfoWriter, BuildStrings) { base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); c16lcpy(expected.BuildString, build_string_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.BuildString)); + ArraySize(expected.BuildString)); base::string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); c16lcpy(expected.DbgBldStr, debug_build_string_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.DbgBldStr)); + ArraySize(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -516,8 +515,8 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { MINIDUMP_MISC_INFO_N tmp; ALLOW_UNUSED_LOCAL(tmp); - std::string build_string(ARRAYSIZE_UNSAFE(tmp.BuildString) + 1, 'B'); - std::string debug_build_string(ARRAYSIZE_UNSAFE(tmp.DbgBldStr), 'D'); + std::string build_string(ArraySize(tmp.BuildString) + 1, 'B'); + std::string debug_build_string(ArraySize(tmp.DbgBldStr), 'D'); misc_info_writer->SetBuildString(build_string, debug_build_string); @@ -534,12 +533,12 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { base::string16 build_string_utf16 = base::UTF8ToUTF16(build_string); c16lcpy(expected.BuildString, build_string_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.BuildString)); + ArraySize(expected.BuildString)); base::string16 debug_build_string_utf16 = base::UTF8ToUTF16(debug_build_string); c16lcpy(expected.DbgBldStr, debug_build_string_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.DbgBldStr)); + ArraySize(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -679,7 +678,7 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); c16lcpy(expected.TimeZone.StandardName, standard_name_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.TimeZone.StandardName)); + ArraySize(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); @@ -687,7 +686,7 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); c16lcpy(expected.TimeZone.DaylightName, daylight_name_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.TimeZone.DaylightName)); + ArraySize(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kSystemTimeZero, sizeof(expected.TimeZone.DaylightDate)); @@ -695,12 +694,12 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); c16lcpy(expected.BuildString, build_string_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.BuildString)); + ArraySize(expected.BuildString)); base::string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); c16lcpy(expected.DbgBldStr, debug_build_string_utf16.c_str(), - ARRAYSIZE_UNSAFE(expected.DbgBldStr)); + ArraySize(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -744,18 +743,18 @@ TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) { expect_misc_info.TimeZone.Bias = 300; c16lcpy(expect_misc_info.TimeZone.StandardName, standard_time_name_utf16.c_str(), - ARRAYSIZE_UNSAFE(expect_misc_info.TimeZone.StandardName)); + ArraySize(expect_misc_info.TimeZone.StandardName)); expect_misc_info.TimeZone.StandardBias = 0; c16lcpy(expect_misc_info.TimeZone.DaylightName, daylight_time_name_utf16.c_str(), - ARRAYSIZE_UNSAFE(expect_misc_info.TimeZone.DaylightName)); + ArraySize(expect_misc_info.TimeZone.DaylightName)); expect_misc_info.TimeZone.DaylightBias = -60; c16lcpy(expect_misc_info.BuildString, build_string_utf16.c_str(), - ARRAYSIZE_UNSAFE(expect_misc_info.BuildString)); + ArraySize(expect_misc_info.BuildString)); c16lcpy(expect_misc_info.DbgBldStr, debug_build_string_utf16.c_str(), - ARRAYSIZE_UNSAFE(expect_misc_info.DbgBldStr)); + ArraySize(expect_misc_info.DbgBldStr)); const timeval kStartTime = { static_cast<time_t>(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 63a9338c..83401eca 100644 --- a/minidump/minidump_module_crashpad_info_writer_test.cc +++ b/minidump/minidump_module_crashpad_info_writer_test.cc @@ -28,6 +28,7 @@ #include "minidump/test/minidump_writable_test_util.h" #include "snapshot/test/test_module_snapshot.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -154,9 +155,9 @@ TEST(MinidumpModuleCrashpadInfoWriter, FullModule) { sizeof(MinidumpSimpleStringDictionaryEntry) + sizeof(MinidumpAnnotationList) + 2 + // padding sizeof(MinidumpAnnotation) + sizeof(MinidumpUTF8String) + - arraysize(kEntry) + 2 + // padding - sizeof(MinidumpUTF8String) + arraysize(kKey) + - sizeof(MinidumpUTF8String) + arraysize(kValue) + + ArraySize(kEntry) + 2 + // padding + sizeof(MinidumpUTF8String) + ArraySize(kKey) + + sizeof(MinidumpUTF8String) + ArraySize(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 0fddfe88..bef6a8c6 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -30,6 +30,7 @@ #include "snapshot/test/test_module_snapshot.h" #include "test/gtest_death.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/misc/uuid.h" @@ -650,10 +651,10 @@ void InitializeTestModuleSnapshotFromMinidumpModule( TEST(MinidumpModuleWriter, InitializeFromSnapshot) { MINIDUMP_MODULE expect_modules[3] = {}; - const char* module_paths[arraysize(expect_modules)] = {}; - const char* module_pdbs[arraysize(expect_modules)] = {}; - UUID uuids[arraysize(expect_modules)] = {}; - uint32_t ages[arraysize(expect_modules)] = {}; + const char* module_paths[ArraySize(expect_modules)] = {}; + const char* module_pdbs[ArraySize(expect_modules)] = {}; + UUID uuids[ArraySize(expect_modules)] = {}; + uint32_t ages[ArraySize(expect_modules)] = {}; expect_modules[0].BaseOfImage = 0x100101000; expect_modules[0].SizeOfImage = 0xf000; @@ -705,7 +706,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { std::vector<std::unique_ptr<TestModuleSnapshot>> module_snapshots_owner; std::vector<const ModuleSnapshot*> module_snapshots; - for (size_t index = 0; index < arraysize(expect_modules); ++index) { + for (size_t index = 0; index < ArraySize(expect_modules); ++index) { module_snapshots_owner.push_back(std::make_unique<TestModuleSnapshot>()); 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 30432871..bd376a9f 100644 --- a/minidump/minidump_rva_list_writer_test.cc +++ b/minidump/minidump_rva_list_writer_test.cc @@ -22,6 +22,7 @@ #include "minidump/test/minidump_rva_list_test_util.h" #include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -86,10 +87,10 @@ TEST(MinidumpRVAListWriter, ThreeChildren) { ASSERT_TRUE(list_writer.WriteEverything(&string_file)); const MinidumpRVAList* list = - MinidumpRVAListAtStart(string_file.string(), arraysize(kValues)); + MinidumpRVAListAtStart(string_file.string(), ArraySize(kValues)); ASSERT_TRUE(list); - for (size_t index = 0; index < arraysize(kValues); ++index) { + for (size_t index = 0; index < ArraySize(kValues); ++index) { SCOPED_TRACE(base::StringPrintf("index %" PRIuS, index)); const uint32_t* child = MinidumpWritableAtRVA<uint32_t>( diff --git a/minidump/minidump_string_writer_test.cc b/minidump/minidump_string_writer_test.cc index 1d654856..aa735039 100644 --- a/minidump/minidump_string_writer_test.cc +++ b/minidump/minidump_string_writer_test.cc @@ -25,6 +25,7 @@ #include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -66,14 +67,14 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { {4, "\360\220\204\202", 2, {0xd800, 0xdd02}}, // 𐄂 (non-BMP) }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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[arraysize(kTestData[index].output_string) - 1], + .output_string[ArraySize(kTestData[index].output_string) - 1], 0); string_file.Reset(); @@ -118,7 +119,7 @@ TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { "\303\0\251", // NUL in middle of valid sequence }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(kTestData); ++index) { SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ", input %s", index, kTestData[index])); string_file.Reset(); @@ -181,7 +182,7 @@ TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { {4, "\360\220\204\202"}, // 𐄂 (non-BMP) }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 cc87d242..df0e348b 100644 --- a/minidump/minidump_system_info_writer.cc +++ b/minidump/minidump_system_info_writer.cc @@ -20,7 +20,7 @@ #include "minidump/minidump_string_writer.h" #include "snapshot/system_snapshot.h" #include "util/file/file_writer.h" -#include "util/misc/arraysize_unsafe.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -212,7 +212,7 @@ void MinidumpSystemInfoWriter::SetCPUX86Vendor(uint32_t ebx, system_info_.ProcessorArchitecture == kMinidumpCPUArchitectureX86Win64); - static_assert(ARRAYSIZE_UNSAFE(system_info_.Cpu.X86CpuInfo.VendorId) == 3, + static_assert(ArraySize(system_info_.Cpu.X86CpuInfo.VendorId) == 3, "VendorId must have 3 elements"); system_info_.Cpu.X86CpuInfo.VendorId[0] = ebx; @@ -230,7 +230,7 @@ void MinidumpSystemInfoWriter::SetCPUX86VendorString( sizeof(registers) == sizeof(system_info_.Cpu.X86CpuInfo.VendorId), "VendorId sizes must be equal"); - for (size_t index = 0; index < arraysize(registers); ++index) { + for (size_t index = 0; index < ArraySize(registers); ++index) { memcpy(®isters[index], &vendor[index * sizeof(*registers)], sizeof(*registers)); @@ -270,9 +270,8 @@ void MinidumpSystemInfoWriter::SetCPUOtherFeatures(uint64_t features_0, system_info_.ProcessorArchitecture != kMinidumpCPUArchitectureX86Win64); - static_assert( - ARRAYSIZE_UNSAFE(system_info_.Cpu.OtherCpuInfo.ProcessorFeatures) == 2, - "ProcessorFeatures must have 2 elements"); + static_assert(ArraySize(system_info_.Cpu.OtherCpuInfo.ProcessorFeatures) == 2, + "ProcessorFeatures must have 2 elements"); system_info_.Cpu.OtherCpuInfo.ProcessorFeatures[0] = features_0; system_info_.Cpu.OtherCpuInfo.ProcessorFeatures[1] = features_1; diff --git a/minidump/minidump_thread_id_map_test.cc b/minidump/minidump_thread_id_map_test.cc index 7c6795a3..d64d8106 100644 --- a/minidump/minidump_thread_id_map_test.cc +++ b/minidump/minidump_thread_id_map_test.cc @@ -21,6 +21,7 @@ #include "base/macros.h" #include "gtest/gtest.h" #include "snapshot/test/test_thread_snapshot.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -38,7 +39,7 @@ class MinidumpThreadIDMapTest : public testing::Test { // testing::Test: void SetUp() override { - for (size_t index = 0; index < arraysize(test_thread_snapshots_); ++index) { + for (size_t index = 0; index < ArraySize(test_thread_snapshots_); ++index) { thread_snapshots_.push_back(&test_thread_snapshots_[index]); } } @@ -59,7 +60,7 @@ class MinidumpThreadIDMapTest : public testing::Test { } void SetThreadID(size_t index, uint64_t thread_id) { - ASSERT_LT(index, arraysize(test_thread_snapshots_)); + ASSERT_LT(index, ArraySize(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 e95c9044..63269ced 100644 --- a/minidump/minidump_thread_writer_test.cc +++ b/minidump/minidump_thread_writer_test.cc @@ -33,6 +33,7 @@ #include "snapshot/test/test_thread_snapshot.h" #include "test/gtest_death.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -522,10 +523,10 @@ template <typename Traits> void RunInitializeFromSnapshotTest(bool thread_id_collision) { using MinidumpContextType = typename Traits::MinidumpContextType; MINIDUMP_THREAD expect_threads[3] = {}; - uint64_t thread_ids[arraysize(expect_threads)] = {}; - uint8_t memory_values[arraysize(expect_threads)] = {}; - uint32_t context_seeds[arraysize(expect_threads)] = {}; - MINIDUMP_MEMORY_DESCRIPTOR tebs[arraysize(expect_threads)] = {}; + uint64_t thread_ids[ArraySize(expect_threads)] = {}; + uint8_t memory_values[ArraySize(expect_threads)] = {}; + uint32_t context_seeds[ArraySize(expect_threads)] = {}; + MINIDUMP_MEMORY_DESCRIPTOR tebs[ArraySize(expect_threads)] = {}; constexpr size_t kTebSize = 1024; @@ -581,7 +582,7 @@ void RunInitializeFromSnapshotTest(bool thread_id_collision) { std::vector<std::unique_ptr<TestThreadSnapshot>> thread_snapshots_owner; std::vector<const ThreadSnapshot*> thread_snapshots; - for (size_t index = 0; index < arraysize(expect_threads); ++index) { + for (size_t index = 0; index < ArraySize(expect_threads); ++index) { thread_snapshots_owner.push_back(std::make_unique<TestThreadSnapshot>()); TestThreadSnapshot* thread_snapshot = thread_snapshots_owner.back().get(); diff --git a/minidump/minidump_writable.cc b/minidump/minidump_writable.cc index d2b58f5b..c8075c61 100644 --- a/minidump/minidump_writable.cc +++ b/minidump/minidump_writable.cc @@ -18,6 +18,7 @@ #include "base/logging.h" #include "util/file/file_writer.h" +#include "util/misc/arraysize.h" #include "util/numeric/safe_assignment.h" namespace { @@ -244,7 +245,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_, arraysize(kZeroes)); + DCHECK_LE(leading_pad_bytes_, ArraySize(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 318b3fc9..ae80d003 100644 --- a/minidump/test/minidump_context_test_util.cc +++ b/minidump/test/minidump_context_test_util.cc @@ -18,12 +18,12 @@ #include <sys/types.h> #include "base/format_macros.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "snapshot/cpu_context.h" #include "snapshot/test/test_cpu_context.h" #include "test/hex_string.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -128,7 +128,7 @@ void InitializeMinidumpContextAMD64(MinidumpContextAMD64* context, context->ds = static_cast<uint16_t>(value++); context->es = static_cast<uint16_t>(value++); context->ss = static_cast<uint16_t>(value++); - for (size_t index = 0; index < arraysize(context->vector_register); ++index) { + for (size_t index = 0; index < ArraySize(context->vector_register); ++index) { context->vector_register[index].lo = value++; context->vector_register[index].hi = value++; } @@ -151,7 +151,7 @@ void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed) { uint32_t value = seed; - for (size_t index = 0; index < arraysize(context->regs); ++index) { + for (size_t index = 0; index < ArraySize(context->regs); ++index) { context->regs[index] = value++; } context->fp = value++; @@ -162,7 +162,7 @@ void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed) { context->pc = value++; context->cpsr = value++; - for (size_t index = 0; index < arraysize(context->vfp); ++index) { + for (size_t index = 0; index < ArraySize(context->vfp); ++index) { context->vfp[index] = value++; } context->fpscr = value++; @@ -180,7 +180,7 @@ void InitializeMinidumpContextARM64(MinidumpContextARM64* context, uint32_t value = seed; - for (size_t index = 0; index < arraysize(context->regs); ++index) { + for (size_t index = 0; index < ArraySize(context->regs); ++index) { context->regs[index] = value++; } context->fp = value++; @@ -189,7 +189,7 @@ void InitializeMinidumpContextARM64(MinidumpContextARM64* context, context->pc = value++; context->cpsr = value++; - for (size_t index = 0; index < arraysize(context->fpsimd); ++index) { + for (size_t index = 0; index < ArraySize(context->fpsimd); ++index) { context->fpsimd[index].lo = value++; context->fpsimd[index].hi = value++; } @@ -209,7 +209,7 @@ void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, uint32_t value = seed; - for (size_t index = 0; index < arraysize(context->regs); ++index) { + for (size_t index = 0; index < ArraySize(context->regs); ++index) { context->regs[index] = value++; } @@ -220,7 +220,7 @@ void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, context->status = value++; context->cause = value++; - for (size_t index = 0; index < arraysize(context->fpregs.fregs); ++index) { + for (size_t index = 0; index < ArraySize(context->fpregs.fregs); ++index) { context->fpregs.fregs[index]._fp_fregs = static_cast<float>(value++); } @@ -247,7 +247,7 @@ void InitializeMinidumpContextMIPS64(MinidumpContextMIPS64* context, uint64_t value = seed; - for (size_t index = 0; index < arraysize(context->regs); ++index) { + for (size_t index = 0; index < ArraySize(context->regs); ++index) { context->regs[index] = value++; } @@ -258,7 +258,7 @@ void InitializeMinidumpContextMIPS64(MinidumpContextMIPS64* context, context->status = value++; context->cause = value++; - for (size_t index = 0; index < arraysize(context->fpregs.dregs); ++index) { + for (size_t index = 0; index < ArraySize(context->fpregs.dregs); ++index) { context->fpregs.dregs[index] = static_cast<double>(value++); } context->fpcsr = value++; @@ -293,35 +293,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 < arraysize(expected->st_mm); + for (size_t st_mm_index = 0; st_mm_index < ArraySize(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, - arraysize(observed->st_mm[st_mm_index].st)), + ArraySize(observed->st_mm[st_mm_index].st)), BytesToHexString(expected->st_mm[st_mm_index].st, - arraysize(expected->st_mm[st_mm_index].st))); + ArraySize(expected->st_mm[st_mm_index].st))); EXPECT_EQ( BytesToHexString(observed->st_mm[st_mm_index].st_reserved, - arraysize(observed->st_mm[st_mm_index].st_reserved)), + ArraySize(observed->st_mm[st_mm_index].st_reserved)), BytesToHexString(expected->st_mm[st_mm_index].st_reserved, - arraysize(expected->st_mm[st_mm_index].st_reserved))); + ArraySize(expected->st_mm[st_mm_index].st_reserved))); } - for (size_t xmm_index = 0; - xmm_index < arraysize(expected->xmm); + for (size_t xmm_index = 0; xmm_index < ArraySize(expected->xmm); ++xmm_index) { EXPECT_EQ(BytesToHexString(observed->xmm[xmm_index], - arraysize(observed->xmm[xmm_index])), + ArraySize(observed->xmm[xmm_index])), BytesToHexString(expected->xmm[xmm_index], - arraysize(expected->xmm[xmm_index]))) + ArraySize(expected->xmm[xmm_index]))) << "xmm_index " << xmm_index; } EXPECT_EQ( - BytesToHexString(observed->reserved_4, arraysize(observed->reserved_4)), - BytesToHexString(expected->reserved_4, arraysize(expected->reserved_4))); + BytesToHexString(observed->reserved_4, ArraySize(observed->reserved_4)), + BytesToHexString(expected->reserved_4, ArraySize(expected->reserved_4))); EXPECT_EQ( - BytesToHexString(observed->available, arraysize(observed->available)), - BytesToHexString(expected->available, arraysize(expected->available))); + BytesToHexString(observed->available, ArraySize(observed->available)), + BytesToHexString(expected->available, ArraySize(expected->available))); } } // namespace @@ -346,11 +344,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 < arraysize(expected.fsave.st); ++index) { + for (size_t index = 0; index < ArraySize(expected.fsave.st); ++index) { EXPECT_EQ(BytesToHexString(observed->fsave.st[index], - arraysize(observed->fsave.st[index])), + ArraySize(observed->fsave.st[index])), BytesToHexString(expected.fsave.st[index], - arraysize(expected.fsave.st[index]))) + ArraySize(expected.fsave.st[index]))) << "index " << index; } if (snapshot) { @@ -449,7 +447,7 @@ void ExpectMinidumpContextAMD64( ExpectMinidumpContextFxsave(&expected.fxsave, &observed->fxsave); - for (size_t index = 0; index < arraysize(expected.vector_register); ++index) { + for (size_t index = 0; index < ArraySize(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 +487,7 @@ void ExpectMinidumpContextARM(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < arraysize(expected.regs); ++index) { + for (size_t index = 0; index < ArraySize(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } EXPECT_EQ(observed->fp, expected.fp); @@ -500,10 +498,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 < arraysize(expected.vfp); ++index) { + for (size_t index = 0; index < ArraySize(expected.vfp); ++index) { EXPECT_EQ(observed->vfp[index], expected.vfp[index]); } - for (size_t index = 0; index < arraysize(expected.extra); ++index) { + for (size_t index = 0; index < ArraySize(expected.extra); ++index) { EXPECT_EQ(observed->extra[index], snapshot ? 0 : expected.extra[index]); } } @@ -516,14 +514,14 @@ void ExpectMinidumpContextARM64(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < arraysize(expected.regs); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(expected.fpsimd); ++index) { + for (size_t index = 0; index < ArraySize(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 +535,7 @@ void ExpectMinidumpContextMIPS(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < arraysize(expected.regs); ++index) { + for (size_t index = 0; index < ArraySize(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } @@ -548,7 +546,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 < arraysize(expected.fpregs.fregs); ++index) { + for (size_t index = 0; index < ArraySize(expected.fpregs.fregs); ++index) { EXPECT_EQ(observed->fpregs.fregs[index]._fp_fregs, expected.fpregs.fregs[index]._fp_fregs); } @@ -570,7 +568,7 @@ void ExpectMinidumpContextMIPS64(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < arraysize(expected.regs); ++index) { + for (size_t index = 0; index < ArraySize(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } @@ -581,7 +579,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 < arraysize(expected.fpregs.dregs); ++index) { + for (size_t index = 0; index < ArraySize(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 98f400e8..3ffbcd2b 100644 --- a/snapshot/capture_memory.cc +++ b/snapshot/capture_memory.cc @@ -20,6 +20,7 @@ #include <memory> #include "snapshot/memory_snapshot.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace internal { @@ -97,17 +98,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 < arraysize(context.arm64->regs); ++i) { + for (size_t i = 0; i < ArraySize(context.arm64->regs); ++i) { MaybeCaptureMemoryAround(delegate, context.arm64->regs[i]); } } else { MaybeCaptureMemoryAround(delegate, context.arm->pc); - for (size_t i = 0; i < arraysize(context.arm->regs); ++i) { + for (size_t i = 0; i < ArraySize(context.arm->regs); ++i) { MaybeCaptureMemoryAround(delegate, context.arm->regs[i]); } } #elif defined(ARCH_CPU_MIPS_FAMILY) - for (size_t i = 0; i < arraysize(context.mipsel->regs); ++i) { + for (size_t i = 0; i < ArraySize(context.mipsel->regs); ++i) { MaybeCaptureMemoryAround(delegate, context.mipsel->regs[i]); } #else diff --git a/snapshot/cpu_context.cc b/snapshot/cpu_context.cc index 4d7c1e5a..0ed16914 100644 --- a/snapshot/cpu_context.cc +++ b/snapshot/cpu_context.cc @@ -18,7 +18,7 @@ #include <string.h> #include "base/logging.h" -#include "base/macros.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -55,9 +55,9 @@ void CPUContextX86::FxsaveToFsave(const Fxsave& fxsave, Fsave* fsave) { fsave->fpu_dp = fxsave.fpu_dp; fsave->fpu_ds = fxsave.fpu_ds; fsave->reserved_4 = 0; - static_assert(arraysize(fsave->st) == arraysize(fxsave.st_mm), + static_assert(ArraySize(fsave->st) == ArraySize(fxsave.st_mm), "FPU stack registers must be equivalent"); - for (size_t index = 0; index < arraysize(fsave->st); ++index) { + for (size_t index = 0; index < ArraySize(fsave->st); ++index) { memcpy(fsave->st[index], fxsave.st_mm[index].st, sizeof(fsave->st[index])); } } @@ -77,9 +77,9 @@ void CPUContextX86::FsaveToFxsave(const Fsave& fsave, Fxsave* fxsave) { fxsave->reserved_3 = 0; fxsave->mxcsr = 0; fxsave->mxcsr_mask = 0; - static_assert(arraysize(fxsave->st_mm) == arraysize(fsave.st), + static_assert(ArraySize(fxsave->st_mm) == ArraySize(fsave.st), "FPU stack registers must be equivalent"); - for (size_t index = 0; index < arraysize(fsave.st); ++index) { + for (size_t index = 0; index < ArraySize(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 706f2fe5..794d9b9f 100644 --- a/snapshot/cpu_context_test.cc +++ b/snapshot/cpu_context_test.cc @@ -18,9 +18,9 @@ #include <string.h> #include <sys/types.h> -#include "base/macros.h" #include "gtest/gtest.h" #include "test/hex_string.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -124,7 +124,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 < arraysize(fxsave.st_mm); ++index) { + for (size_t index = 0; index < ArraySize(fxsave.st_mm); ++index) { memset(&fxsave.st_mm[index].st_reserved, 0x5a, sizeof(fxsave.st_mm[index].st_reserved)); @@ -148,10 +148,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 < arraysize(fsave.st); ++index) { - EXPECT_EQ(BytesToHexString(fsave.st[index], arraysize(fsave.st[index])), + for (size_t index = 0; index < ArraySize(fsave.st); ++index) { + EXPECT_EQ(BytesToHexString(fsave.st[index], ArraySize(fsave.st[index])), BytesToHexString(fxsave.st_mm[index].st, - arraysize(fxsave.st_mm[index].st))) + ArraySize(fxsave.st_mm[index].st))) << "index " << index; } } @@ -204,14 +204,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 < arraysize(fxsave.st_mm); ++index) { + for (size_t index = 0; index < ArraySize(fxsave.st_mm); ++index) { EXPECT_EQ(BytesToHexString(fxsave.st_mm[index].st, - arraysize(fxsave.st_mm[index].st)), - BytesToHexString(fsave.st[index], arraysize(fsave.st[index]))) + ArraySize(fxsave.st_mm[index].st)), + BytesToHexString(fsave.st[index], ArraySize(fsave.st[index]))) << "index " << index; EXPECT_EQ(BytesToHexString(fxsave.st_mm[index].st_reserved, - arraysize(fxsave.st_mm[index].st_reserved)), - std::string(arraysize(fxsave.st_mm[index].st_reserved) * 2, '0')) + ArraySize(fxsave.st_mm[index].st_reserved)), + std::string(ArraySize(fxsave.st_mm[index].st_reserved) * 2, '0')) << "index " << index; } size_t unused_len = sizeof(fxsave) - offsetof(decltype(fxsave), xmm); @@ -318,7 +318,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 < arraysize(st_mm); ++index) { + for (size_t index = 0; index < ArraySize(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 cf2ee61d..45d39d2a 100644 --- a/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc @@ -15,6 +15,7 @@ #include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h" #include "base/logging.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace internal { @@ -49,7 +50,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, arraysize(mapping)); + DCHECK_LT(index, ArraySize(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 df20bd33..5832a221 100644 --- a/snapshot/fuchsia/process_reader_fuchsia_test.cc +++ b/snapshot/fuchsia/process_reader_fuchsia_test.cc @@ -24,6 +24,7 @@ #include "test/multiprocess_exec.h" #include "test/test_paths.h" #include "util/fuchsia/scoped_task_suspend.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -34,7 +35,7 @@ TEST(ProcessReaderFuchsia, SelfBasic) { ASSERT_TRUE(process_reader.Initialize(*zx::process::self())); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[arraysize(kTestMemory)]; + char buffer[ArraySize(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast<zx_vaddr_t>(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 0f3e3bdc..ebb612be 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc @@ -24,6 +24,7 @@ #include "snapshot/fuchsia/process_snapshot_fuchsia.h" #include "test/multiprocess_exec.h" #include "util/fuchsia/scoped_task_suspend.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -103,8 +104,8 @@ class AddressSpaceTest : public MultiprocessExec { private: void MultiprocessParent() override { - uintptr_t test_addresses[arraysize(kTestMappingPermAndSizes)]; - for (size_t i = 0; i < arraysize(test_addresses); ++i) { + uintptr_t test_addresses[ArraySize(kTestMappingPermAndSizes)]; + for (size_t i = 0; i < ArraySize(test_addresses); ++i) { ASSERT_TRUE(ReadFileExactly( ReadPipeHandle(), &test_addresses[i], sizeof(test_addresses[i]))); } @@ -114,7 +115,7 @@ class AddressSpaceTest : public MultiprocessExec { ProcessSnapshotFuchsia process_snapshot; ASSERT_TRUE(process_snapshot.Initialize(*ChildProcess())); - for (size_t i = 0; i < arraysize(test_addresses); ++i) { + for (size_t i = 0; i < ArraySize(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 72d36d8a..e632bc1c 100644 --- a/snapshot/linux/exception_snapshot_linux_test.cc +++ b/snapshot/linux/exception_snapshot_linux_test.cc @@ -32,6 +32,7 @@ #include "test/errors.h" #include "test/linux/fake_ptrace_connection.h" #include "util/linux/address_types.h" +#include "util/misc/arraysize.h" #include "util/misc/clock.h" #include "util/misc/from_pointer_cast.h" #include "util/posix/signals.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 < arraysize(test_context->vfp.context.vfp.fpregs); + for (size_t reg = 0; reg < ArraySize(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 < arraysize(context->uc_mcontext.regs); + for (size_t index = 0; index < ArraySize(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 < arraysize(test_context->fpsimd.vregs); ++reg) { + for (size_t reg = 0; reg < ArraySize(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 < arraysize(context->uc_mcontext.gregs); ++reg) { + for (size_t reg = 0; reg < ArraySize(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 < arraysize(expected.uc_mcontext.gregs); ++reg) { + for (size_t reg = 0; reg < ArraySize(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 1edc5ab2..61b84f39 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -47,6 +47,7 @@ #include "util/file/filesystem.h" #include "util/linux/direct_ptrace_connection.h" #include "util/misc/address_sanitizer.h" +#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/synchronization/semaphore.h" @@ -79,7 +80,7 @@ TEST(ProcessReaderLinux, SelfBasic) { EXPECT_EQ(process_reader.ParentProcessID(), getppid()); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[arraysize(kTestMemory)]; + char buffer[ArraySize(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast<LinuxVMAddress>(kTestMemory), sizeof(kTestMemory), diff --git a/snapshot/mac/mach_o_image_reader.cc b/snapshot/mac/mach_o_image_reader.cc index 6baee770..650b0c77 100644 --- a/snapshot/mac/mach_o_image_reader.cc +++ b/snapshot/mac/mach_o_image_reader.cc @@ -28,6 +28,7 @@ #include "snapshot/mac/mach_o_image_symbol_table_reader.h" #include "snapshot/mac/process_reader_mac.h" #include "util/mac/checked_mach_address_range.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace { @@ -182,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<uint32_t> singleton_indices(arraysize(kLoadCommandReaders), + std::vector<uint32_t> singleton_indices(ArraySize(kLoadCommandReaders), kInvalidSegmentIndex); size_t offset = mach_header.Size(); @@ -235,8 +236,7 @@ bool MachOImageReader::Initialize(ProcessReaderMac* process_reader, return false; } - for (size_t reader_index = 0; - reader_index < arraysize(kLoadCommandReaders); + for (size_t reader_index = 0; reader_index < ArraySize(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 2da97e85..cfbddc1e 100644 --- a/snapshot/mac/mach_o_image_segment_reader_test.cc +++ b/snapshot/mac/mach_o_image_segment_reader_test.cc @@ -16,9 +16,9 @@ #include <mach-o/loader.h> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -63,7 +63,7 @@ TEST(MachOImageSegmentReader, SegmentNameString) { SEG_IMPORT, }; - for (size_t index = 0; index < arraysize(kSegmentTestData); ++index) { + for (size_t index = 0; index < ArraySize(kSegmentTestData); ++index) { EXPECT_EQ( MachOImageSegmentReader::SegmentNameString(kSegmentTestData[index]), kSegmentTestData[index]) @@ -106,7 +106,7 @@ TEST(MachOImageSegmentReader, SectionNameString) { SECT_ICON_TIFF, }; - for (size_t index = 0; index < arraysize(kSectionTestData); ++index) { + for (size_t index = 0; index < ArraySize(kSectionTestData); ++index) { EXPECT_EQ( MachOImageSegmentReader::SectionNameString(kSectionTestData[index]), kSectionTestData[index]) @@ -169,7 +169,7 @@ TEST(MachOImageSegmentReader, SegmentAndSectionNameString) { {SEG_IMPORT, "", "__IMPORT,"}, }; - for (size_t index = 0; index < arraysize(kSegmentAndSectionTestData); + for (size_t index = 0; index < ArraySize(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 cf3604cf..e3f4df17 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -41,6 +41,7 @@ #include "util/file/file_io.h" #include "util/mac/mac_util.h" #include "util/mach/mach_extensions.h" +#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/synchronization/semaphore.h" @@ -64,7 +65,7 @@ TEST(ProcessReaderMac, SelfBasic) { EXPECT_EQ(process_reader.ParentProcessID(), getppid()); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[arraysize(kTestMemory)]; + char buffer[ArraySize(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( FromPointerCast<mach_vm_address_t>(kTestMemory), sizeof(kTestMemory), @@ -612,11 +613,11 @@ class ScopedOpenCLNoOpKernel { const size_t source_lengths[] = { strlen(sources[0]), }; - static_assert(arraysize(sources) == arraysize(source_lengths), + static_assert(ArraySize(sources) == ArraySize(source_lengths), "arrays must be parallel"); program_ = clCreateProgramWithSource( - context_, arraysize(sources), sources, source_lengths, &rv); + context_, ArraySize(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 cbb114d7..9ae8f7c2 100644 --- a/snapshot/mac/process_types.cc +++ b/snapshot/mac/process_types.cc @@ -20,8 +20,8 @@ #include <memory> -#include "base/macros.h" #include "snapshot/mac/process_types/internal.h" +#include "util/misc/arraysize.h" #include "util/process/process_memory_mac.h" namespace crashpad { @@ -74,7 +74,7 @@ using UInt64Array4 = uint64_t[4]; template <> inline void Assign<UInt64Array4, UInt32Array4>(UInt64Array4* destination, const UInt32Array4& source) { - for (size_t index = 0; index < arraysize(source); ++index) { + for (size_t index = 0; index < ArraySize(source); ++index) { (*destination)[index] = source[index]; } } diff --git a/snapshot/mac/process_types/custom.cc b/snapshot/mac/process_types/custom.cc index 90209654..3d5976cc 100644 --- a/snapshot/mac/process_types/custom.cc +++ b/snapshot/mac/process_types/custom.cc @@ -25,6 +25,7 @@ #include "base/numerics/safe_math.h" #include "base/strings/stringprintf.h" #include "snapshot/mac/process_types/internal.h" +#include "util/misc/arraysize.h" #include "util/process/process_memory_mac.h" #if !DOXYGEN @@ -144,8 +145,8 @@ size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion( sizeof(dyld_all_image_infos<Traits>), // 16 }; - if (version >= arraysize(kSizeForVersion)) { - return kSizeForVersion[arraysize(kSizeForVersion) - 1]; + if (version >= ArraySize(kSizeForVersion)) { + return kSizeForVersion[ArraySize(kSizeForVersion) - 1]; } static_assert(std::is_unsigned<decltype(version)>::value, diff --git a/snapshot/mac/process_types_test.cc b/snapshot/mac/process_types_test.cc index f116c4dd..9a9dc9d4 100644 --- a/snapshot/mac/process_types_test.cc +++ b/snapshot/mac/process_types_test.cc @@ -20,13 +20,13 @@ #include <vector> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/mac/process_types/internal.h" #include "test/mac/dyld.h" #include "util/mac/mac_util.h" +#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/misc/implicit_cast.h" @@ -147,7 +147,7 @@ TEST(ProcessTypes, DyldImagesSelf) { {15, 164, 304}, {16, 176, 320}, }; - for (size_t index = 0; index < arraysize(kVersionsAndSizes); ++index) { + for (size_t index = 0; index < ArraySize(kVersionsAndSizes); ++index) { uint32_t version = kVersionsAndSizes[index].version; SCOPED_TRACE(base::StringPrintf("index %zu, version %u", index, version)); @@ -268,8 +268,7 @@ TEST(ProcessTypes, DyldImagesSelf) { self_image_infos->sharedCacheBaseAddress); EXPECT_EQ(proctype_image_infos.dyldPath, reinterpret_cast<uint64_t>(self_image_infos->dyldPath)); - for (size_t index = 0; - index < arraysize(self_image_infos->notifyPorts); + for (size_t index = 0; index < ArraySize(self_image_infos->notifyPorts); ++index) { EXPECT_EQ(proctype_image_infos.notifyPorts[index], self_image_infos->notifyPorts[index]) @@ -289,8 +288,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 < arraysize(proctype_image_infos.reserved); + for (size_t index = 0; index < ArraySize(proctype_image_infos.reserved); ++index) { EXPECT_EQ(proctype_image_infos.reserved[index], implicit_cast<uint64_t>(self_image_infos->reserved[index])) diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 52b09920..47876036 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -28,6 +28,7 @@ #include "snapshot/minidump/minidump_annotation_reader.h" #include "snapshot/module_snapshot.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" #include "util/misc/pdb_structures.h" namespace crashpad { @@ -858,27 +859,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 < arraysize(minidump_context.vector_register); i++) { + for (size_t i = 0; i < ArraySize(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 < arraysize(minidump_context.fxsave.reserved_4); i++) { + for (uint8_t i = 0; i < ArraySize(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 < arraysize(minidump_context.fxsave.st_mm); i++) { + for (size_t i = 0; i < ArraySize(minidump_context.fxsave.st_mm); i++) { for (uint8_t j = 0; - j < arraysize(minidump_context.fxsave.st_mm[0].mm_value); + j < ArraySize(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 < arraysize(minidump_context.fxsave.xmm); i++) { - for (uint8_t j = 0; j < arraysize(minidump_context.fxsave.xmm[0]); j++) { + for (size_t i = 0; i < ArraySize(minidump_context.fxsave.xmm); i++) { + for (uint8_t j = 0; j < ArraySize(minidump_context.fxsave.xmm[0]); j++) { minidump_context.fxsave.xmm[i][j] = j + 1; } } @@ -961,22 +962,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 < arraysize(ctx->fxsave.reserved_4); i++) { + for (uint8_t i = 0; i < ArraySize(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 < arraysize(ctx->fxsave.st_mm); i++) { - for (uint8_t j = 0; - j < arraysize(ctx->fxsave.st_mm[0].mm_value); - j++) { + for (size_t i = 0; i < ArraySize(ctx->fxsave.st_mm); i++) { + for (uint8_t j = 0; j < ArraySize(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 < arraysize(ctx->fxsave.xmm); i++) { - for (uint8_t j = 0; j < arraysize(ctx->fxsave.xmm[0]); j++) { + for (size_t i = 0; i < ArraySize(ctx->fxsave.xmm); i++) { + for (uint8_t j = 0; j < ArraySize(ctx->fxsave.xmm[0]); j++) { EXPECT_EQ(ctx->fxsave.xmm[i][j], j + 1); } } diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc index 00e0e9bf..46ae97a0 100644 --- a/snapshot/minidump/thread_snapshot_minidump.cc +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -18,6 +18,7 @@ #include <string.h> #include "minidump/minidump_context.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace internal { @@ -192,7 +193,7 @@ bool ThreadSnapshotMinidump::InitializeContext( return false; } - for (size_t i = 0; i < arraysize(src->regs); i++) { + for (size_t i = 0; i < ArraySize(src->regs); i++) { context_.arm->regs[i] = src->regs[i]; } @@ -204,7 +205,7 @@ bool ThreadSnapshotMinidump::InitializeContext( context_.arm->cpsr = src->cpsr; context_.arm->vfp_regs.fpscr = src->fpscr; - for (size_t i = 0; i < arraysize(src->vfp); i++) { + for (size_t i = 0; i < ArraySize(src->vfp); i++) { context_.arm->vfp_regs.vfp[i] = src->vfp[i]; } @@ -224,14 +225,14 @@ bool ThreadSnapshotMinidump::InitializeContext( return false; } - for (size_t i = 0; i < arraysize(src->regs); i++) { + for (size_t i = 0; i < ArraySize(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 < arraysize(src->fpsimd); i++) { + for (size_t i = 0; i < ArraySize(src->fpsimd); i++) { context_.arm64->fpsimd[i] = src->fpsimd[i]; } @@ -254,7 +255,7 @@ bool ThreadSnapshotMinidump::InitializeContext( return false; } - for (size_t i = 0; i < arraysize(src->regs); i++) { + for (size_t i = 0; i < ArraySize(src->regs); i++) { context_.mipsel->regs[i] = src->regs[i]; } @@ -262,7 +263,7 @@ bool ThreadSnapshotMinidump::InitializeContext( context_.mipsel->mdlo = static_cast<uint32_t>(src->mdlo); context_.mipsel->dsp_control = src->dsp_control; - for (size_t i = 0; i < arraysize(src->hi); i++) { + for (size_t i = 0; i < ArraySize(src->hi); i++) { context_.mipsel->hi[i] = src->hi[i]; context_.mipsel->lo[i] = src->lo[i]; } @@ -291,7 +292,7 @@ bool ThreadSnapshotMinidump::InitializeContext( return false; } - for (size_t i = 0; i < arraysize(src->regs); i++) { + for (size_t i = 0; i < ArraySize(src->regs); i++) { context_.mips64->regs[i] = src->regs[i]; } @@ -299,7 +300,7 @@ bool ThreadSnapshotMinidump::InitializeContext( context_.mips64->mdlo = src->mdlo; context_.mips64->dsp_control = src->dsp_control; - for (size_t i = 0; i < arraysize(src->hi); i++) { + for (size_t i = 0; i < ArraySize(src->hi); i++) { context_.mips64->hi[i] = src->hi[i]; context_.mips64->lo[i] = src->lo[i]; } diff --git a/snapshot/posix/timezone.cc b/snapshot/posix/timezone.cc index 47c6ecfa..8b2b8221 100644 --- a/snapshot/posix/timezone.cc +++ b/snapshot/posix/timezone.cc @@ -19,6 +19,7 @@ #include "base/logging.h" #include "build/build_config.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace internal { @@ -59,8 +60,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 < arraysize(kMonthDeltas) && !found_transition; + for (size_t index = 0; index < ArraySize(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 814506fa..1bb19c4e 100644 --- a/snapshot/posix/timezone_test.cc +++ b/snapshot/posix/timezone_test.cc @@ -25,6 +25,7 @@ #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/errors.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -154,7 +155,7 @@ TEST(TimeZone, Basic) { {"UTC", false, 0, 0, "UTC", "UTC"}, }; - for (size_t index = 0; index < arraysize(kTestTimeZones); ++index) { + for (size_t index = 0; index < ArraySize(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/sanitization_information_test.cc b/snapshot/sanitized/sanitization_information_test.cc index a7bf8265..c7d836a5 100644 --- a/snapshot/sanitized/sanitization_information_test.cc +++ b/snapshot/sanitized/sanitization_information_test.cc @@ -16,6 +16,7 @@ #include "build/build_config.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_linux.h" @@ -59,8 +60,8 @@ const char* const kNonEmptyWhitelist[] = {"string1", TEST_F(WhitelistTest, NonEmptyWhitelist) { ASSERT_TRUE(ReadWhitelist(kNonEmptyWhitelist)); - ASSERT_EQ(whitelist_.size(), arraysize(kNonEmptyWhitelist) - 1); - for (size_t index = 0; index < arraysize(kNonEmptyWhitelist) - 1; ++index) { + ASSERT_EQ(whitelist_.size(), ArraySize(kNonEmptyWhitelist) - 1); + for (size_t index = 0; index < ArraySize(kNonEmptyWhitelist) - 1; ++index) { EXPECT_EQ(whitelist_[index], kNonEmptyWhitelist[index]); } } diff --git a/snapshot/test/test_cpu_context.cc b/snapshot/test/test_cpu_context.cc index 8e712b7a..7694d7eb 100644 --- a/snapshot/test/test_cpu_context.cc +++ b/snapshot/test/test_cpu_context.cc @@ -17,7 +17,7 @@ #include <string.h> #include <sys/types.h> -#include "base/macros.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -44,28 +44,28 @@ void InitializeCPUContextFxsave(FxsaveType* fxsave, uint32_t* seed) { fxsave->reserved_3 = static_cast<uint16_t>(value++); fxsave->mxcsr = value++; fxsave->mxcsr_mask = value++; - for (size_t st_mm_index = 0; st_mm_index < arraysize(fxsave->st_mm); + for (size_t st_mm_index = 0; st_mm_index < ArraySize(fxsave->st_mm); ++st_mm_index) { - for (size_t byte = 0; byte < arraysize(fxsave->st_mm[st_mm_index].st); + for (size_t byte = 0; byte < ArraySize(fxsave->st_mm[st_mm_index].st); ++byte) { fxsave->st_mm[st_mm_index].st[byte] = static_cast<uint8_t>(value++); } for (size_t byte = 0; - byte < arraysize(fxsave->st_mm[st_mm_index].st_reserved); + byte < ArraySize(fxsave->st_mm[st_mm_index].st_reserved); ++byte) { fxsave->st_mm[st_mm_index].st_reserved[byte] = static_cast<uint8_t>(value); } } - for (size_t xmm_index = 0; xmm_index < arraysize(fxsave->xmm); ++xmm_index) { - for (size_t byte = 0; byte < arraysize(fxsave->xmm[xmm_index]); ++byte) { + for (size_t xmm_index = 0; xmm_index < ArraySize(fxsave->xmm); ++xmm_index) { + for (size_t byte = 0; byte < ArraySize(fxsave->xmm[xmm_index]); ++byte) { fxsave->xmm[xmm_index][byte] = static_cast<uint8_t>(value++); } } - for (size_t byte = 0; byte < arraysize(fxsave->reserved_4); ++byte) { + for (size_t byte = 0; byte < ArraySize(fxsave->reserved_4); ++byte) { fxsave->reserved_4[byte] = static_cast<uint8_t>(value++); } - for (size_t byte = 0; byte < arraysize(fxsave->available); ++byte) { + for (size_t byte = 0; byte < ArraySize(fxsave->available); ++byte) { fxsave->available[byte] = static_cast<uint8_t>(value++); } @@ -174,7 +174,7 @@ void InitializeCPUContextARM(CPUContext* context, uint32_t seed) { uint32_t value = seed; - for (size_t index = 0; index < arraysize(arm->regs); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(arm->vfp_regs.vfp); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(arm64->regs); ++index) { + for (size_t index = 0; index < ArraySize(arm64->regs); ++index) { arm64->regs[index] = value++; } arm64->sp = value++; arm64->pc = value++; arm64->spsr = value++; - for (size_t index = 0; index < arraysize(arm64->fpsimd); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(mipsel->regs); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(mipsel->fpregs.fregs); ++index) { + for (size_t index = 0; index < ArraySize(mipsel->fpregs.fregs); ++index) { mipsel->fpregs.fregs[index]._fp_fregs = static_cast<float>(value++); } @@ -267,7 +267,7 @@ void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed) { uint64_t value = seed; - for (size_t index = 0; index < arraysize(mips64->regs); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(mips64->fpregs.dregs); ++index) { + for (size_t index = 0; index < ArraySize(mips64->fpregs.dregs); ++index) { mips64->fpregs.dregs[index] = static_cast<double>(value++); } diff --git a/snapshot/win/cpu_context_win_test.cc b/snapshot/win/cpu_context_win_test.cc index aa2afe9b..7f66f9d3 100644 --- a/snapshot/win/cpu_context_win_test.cc +++ b/snapshot/win/cpu_context_win_test.cc @@ -16,11 +16,11 @@ #include <windows.h> -#include "base/macros.h" #include "build/build_config.h" #include "gtest/gtest.h" -#include "test/hex_string.h" #include "snapshot/cpu_context.h" +#include "test/hex_string.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -87,13 +87,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, - arraysize(cpu_context_x86.fxsave.st_mm[st_mm].st)), - std::string(arraysize(cpu_context_x86.fxsave.st_mm[st_mm].st) * 2, + ArraySize(cpu_context_x86.fxsave.st_mm[st_mm].st)), + std::string(ArraySize(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, - arraysize(cpu_context_x86.fxsave.st_mm[7].st)), + ArraySize(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 4ebd98e9..e6a9e5d6 100644 --- a/snapshot/win/crashpad_snapshot_test_image_reader.cc +++ b/snapshot/win/crashpad_snapshot_test_image_reader.cc @@ -17,6 +17,7 @@ #include "base/logging.h" #include "client/crashpad_info.h" #include "util/file/file_io.h" +#include "util/misc/arraysize.h" #include "util/synchronization/semaphore.h" #include "util/win/scoped_handle.h" @@ -28,7 +29,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 < arraysize(pointers); ++i) { + for (size_t i = 0; i < ArraySize(pointers); ++i) { pointers[i] = new int[2048]; } @@ -52,7 +53,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 < arraysize(threads); ++i) { + for (size_t i = 0; i < ArraySize(threads); ++i) { threads[i].reset(CreateThread(nullptr, 0, &LotsOfReferencesThreadProc, @@ -65,7 +66,7 @@ int wmain(int argc, wchar_t* argv[]) { } } - for (size_t i = 0; i < arraysize(threads); ++i) { + for (size_t i = 0; i < ArraySize(threads); ++i) { semaphore.Wait(); } diff --git a/snapshot/win/pe_image_annotations_reader.cc b/snapshot/win/pe_image_annotations_reader.cc index 4c1f66fd..c5e53735 100644 --- a/snapshot/win/pe_image_annotations_reader.cc +++ b/snapshot/win/pe_image_annotations_reader.cc @@ -23,6 +23,7 @@ #include "snapshot/snapshot_constants.h" #include "snapshot/win/pe_image_reader.h" #include "snapshot/win/process_reader_win.h" +#include "util/misc/arraysize.h" #include "util/win/process_structs.h" namespace crashpad { @@ -155,7 +156,7 @@ void PEImageAnnotationsReader::ReadCrashpadAnnotationsList( snapshot.type = current.type; char name[Annotation::kNameMaxLength]; - if (!process_reader_->Memory()->Read(current.name, arraysize(name), name)) { + if (!process_reader_->Memory()->Read(current.name, ArraySize(name), name)) { LOG(WARNING) << "could not read annotation name at index " << index << " in " << base::UTF16ToUTF8(name_); continue; diff --git a/snapshot/win/pe_image_reader.cc b/snapshot/win/pe_image_reader.cc index e705bb51..094cf0fd 100644 --- a/snapshot/win/pe_image_reader.cc +++ b/snapshot/win/pe_image_reader.cc @@ -24,6 +24,7 @@ #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" #include "snapshot/win/pe_image_resource_reader.h" +#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/misc/pdb_structures.h" #include "util/win/process_structs.h" @@ -275,7 +276,7 @@ bool PEImageReader::VSFixedFileInfo( version_info.wType != 0 || wcsncmp(version_info.szKey, L"VS_VERSION_INFO", - arraysize(version_info.szKey)) != 0) { + ArraySize(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 b0601e8b..eca6f486 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -19,6 +19,7 @@ #include "gtest/gtest.h" #include "test/win/win_multiprocess.h" +#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/synchronization/semaphore.h" #include "util/thread/thread.h" @@ -43,7 +44,7 @@ TEST(ProcessReaderWin, SelfBasic) { EXPECT_EQ(process_reader.GetProcessInfo().ProcessID(), GetCurrentProcessId()); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[arraysize(kTestMemory)]; + char buffer[ArraySize(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast<uintptr_t>(kTestMemory), sizeof(kTestMemory), &buffer)); EXPECT_STREQ(kTestMemory, buffer); @@ -184,7 +185,7 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { // the pipe. CheckedReadFileAtEOF(ReadPipeHandle()); - for (size_t i = 0; i < arraysize(threads); ++i) + for (size_t i = 0; i < ArraySize(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 94dd22b5..5d98a5f7 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -24,6 +24,7 @@ #include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/misc/time.h" #include "util/win/nt_internals.h" @@ -334,7 +335,7 @@ void ProcessSnapshotWin::InitializeUnloadedModules() { uet.TimeDateStamp, base::UTF16ToUTF8(base::StringPiece16( uet.ImageName, - wcsnlen(uet.ImageName, arraysize(uet.ImageName)))))); + wcsnlen(uet.ImageName, ArraySize(uet.ImageName)))))); } } } @@ -534,9 +535,9 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock( env_block.resize( static_cast<unsigned int>(bytes_read / sizeof(env_block[0]))); static constexpr wchar_t terminator[] = {0, 0}; - size_t at = env_block.find(std::wstring(terminator, arraysize(terminator))); + size_t at = env_block.find(std::wstring(terminator, ArraySize(terminator))); if (at != std::wstring::npos) - env_block.resize(at + arraysize(terminator)); + env_block.resize(at + ArraySize(terminator)); return env_block.size() * sizeof(env_block[0]); } diff --git a/test/hex_string.h b/test/hex_string.h index 435a692e..2d7801b9 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, arraysize(observed)), -//! BytesToHexString(expected, arraysize(expected))); +//! EXPECT_EQ(BytesToHexString(observed, ArraySize(observed)), +//! BytesToHexString(expected, ArraySize(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 68745e6f..3d44cc9f 100644 --- a/test/hex_string_test.cc +++ b/test/hex_string_test.cc @@ -14,8 +14,8 @@ #include "test/hex_string.h" -#include "base/macros.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -25,7 +25,7 @@ TEST(HexString, HexString) { EXPECT_EQ(BytesToHexString(nullptr, 0), ""); static constexpr char kBytes[] = "Abc123xyz \x0a\x7f\xf0\x9f\x92\xa9_"; - EXPECT_EQ(BytesToHexString(kBytes, arraysize(kBytes)), + EXPECT_EQ(BytesToHexString(kBytes, ArraySize(kBytes)), "41626331323378797a200a7ff09f92a95f00"); } diff --git a/tools/crashpad_database_util.cc b/tools/crashpad_database_util.cc index b4c2a15b..d8274c56 100644 --- a/tools/crashpad_database_util.cc +++ b/tools/crashpad_database_util.cc @@ -28,7 +28,6 @@ #include "base/files/file_path.h" #include "base/logging.h" -#include "base/macros.h" #include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" @@ -37,6 +36,7 @@ #include "tools/tool_support.h" #include "util/file/file_io.h" #include "util/file/file_reader.h" +#include "util/misc/arraysize.h" #include "util/misc/uuid.h" #include "util/stdlib/string_number_conversion.h" @@ -109,14 +109,14 @@ bool StringToBool(const char* string, bool* boolean) { "set", }; - for (size_t index = 0; index < arraysize(kFalseWords); ++index) { + for (size_t index = 0; index < ArraySize(kFalseWords); ++index) { if (strcasecmp(string, kFalseWords[index]) == 0) { *boolean = false; return true; } } - for (size_t index = 0; index < arraysize(kTrueWords); ++index) { + for (size_t index = 0; index < ArraySize(kTrueWords); ++index) { if (strcasecmp(string, kTrueWords[index]) == 0) { *boolean = true; return true; @@ -159,7 +159,7 @@ bool StringToTime(const char* string, time_t* out_time, bool utc) { "%+", }; - for (size_t index = 0; index < arraysize(kFormats); ++index) { + for (size_t index = 0; index < ArraySize(kFormats); ++index) { tm time_tm; const char* strptime_result = strptime(string, kFormats[index], &time_tm); if (strptime_result == end) { @@ -214,7 +214,7 @@ std::string TimeToString(time_t out_time, bool utc) { char string[64]; CHECK_NE( - strftime(string, arraysize(string), "%Y-%m-%d %H:%M:%S %Z", &time_tm), + strftime(string, ArraySize(string), "%Y-%m-%d %H:%M:%S %Z", &time_tm), 0u); return std::string(string); diff --git a/util/BUILD.gn b/util/BUILD.gn index c7c6837b..b5e1561a 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -86,7 +86,7 @@ static_library("util") { "file/string_file.h", "misc/address_sanitizer.h", "misc/address_types.h", - "misc/arraysize_unsafe.h", + "misc/arraysize.h", "misc/as_underlying_type.h", "misc/capture_context.h", "misc/clock.h", @@ -530,7 +530,7 @@ source_set("util_test") { "file/file_reader_test.cc", "file/filesystem_test.cc", "file/string_file_test.cc", - "misc/arraysize_unsafe_test.cc", + "misc/arraysize_test.cc", "misc/capture_context_test.cc", "misc/capture_context_test_util.h", "misc/clock_test.cc", diff --git a/util/file/delimited_file_reader.cc b/util/file/delimited_file_reader.cc index a55c2a7c..2a8678f0 100644 --- a/util/file/delimited_file_reader.cc +++ b/util/file/delimited_file_reader.cc @@ -21,6 +21,7 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" +#include "util/misc/arraysize.h" namespace crashpad { @@ -75,7 +76,7 @@ DelimitedFileReader::Result DelimitedFileReader::GetDelim(char delimiter, return Result::kEndOfFile; } - DCHECK_LE(static_cast<size_t>(read_result), arraysize(buf_)); + DCHECK_LE(static_cast<size_t>(read_result), ArraySize(buf_)); DCHECK( base::IsValueInRangeForNumericType<decltype(buf_len_)>(read_result)); buf_len_ = static_cast<decltype(buf_len_)>(read_result); diff --git a/util/file/delimited_file_reader_test.cc b/util/file/delimited_file_reader_test.cc index 79e331f7..b226f3d0 100644 --- a/util/file/delimited_file_reader_test.cc +++ b/util/file/delimited_file_reader_test.cc @@ -20,6 +20,7 @@ #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/file/string_file.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -259,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, arraysize(kString) - 1)); + string_file.SetString(std::string(kString, ArraySize(kString) - 1)); DelimitedFileReader delimited_file_reader(&string_file); std::string line; @@ -277,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, arraysize(kString) - 1)); + string_file.SetString(std::string(kString, ArraySize(kString) - 1)); DelimitedFileReader delimited_file_reader(&string_file); std::string field; @@ -301,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 < arraysize(kSizes); ++index) { + for (size_t index = 0; index < ArraySize(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 4446c320..d341a5d8 100644 --- a/util/file/file_io_test.cc +++ b/util/file/file_io_test.cc @@ -27,6 +27,7 @@ #include "test/errors.h" #include "test/file.h" #include "test/scoped_temp_dir.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/thread/thread.h" @@ -612,7 +613,7 @@ void LockingTest(FileLocking main_lock, FileLocking other_locks) { LockingTestThread threads[20]; int expected_iterations = 0; - for (size_t index = 0; index < arraysize(threads); ++index) { + for (size_t index = 0; index < ArraySize(threads); ++index) { int iterations_for_this_thread = static_cast<int>(index * 10); threads[index].Init( (other_locks == FileLocking::kShared) diff --git a/util/linux/direct_ptrace_connection.cc b/util/linux/direct_ptrace_connection.cc index ac44bf13..371bed2e 100644 --- a/util/linux/direct_ptrace_connection.cc +++ b/util/linux/direct_ptrace_connection.cc @@ -22,6 +22,7 @@ #include "base/strings/string_number_conversions.h" #include "util/file/directory_reader.h" #include "util/file/file_io.h" +#include "util/misc/arraysize.h" #include "util/misc/as_underlying_type.h" namespace crashpad { @@ -92,7 +93,7 @@ bool DirectPtraceConnection::Threads(std::vector<pid_t>* threads) { DCHECK(threads->empty()); char path[32]; - snprintf(path, arraysize(path), "/proc/%d/task", pid_); + snprintf(path, ArraySize(path), "/proc/%d/task", pid_); DirectoryReader reader; if (!reader.Open(base::FilePath(path))) { return false; diff --git a/util/linux/proc_stat_reader.cc b/util/linux/proc_stat_reader.cc index 795e5139..60f10546 100644 --- a/util/linux/proc_stat_reader.cc +++ b/util/linux/proc_stat_reader.cc @@ -21,6 +21,7 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "util/file/file_io.h" +#include "util/misc/arraysize.h" #include "util/misc/lexing.h" #include "util/misc/time.h" @@ -47,7 +48,7 @@ bool ProcStatReader::Initialize(PtraceConnection* connection, pid_t tid) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); char path[32]; - snprintf(path, arraysize(path), "/proc/%d/stat", tid); + snprintf(path, ArraySize(path), "/proc/%d/stat", tid); if (!connection->ReadFileContents(base::FilePath(path), &contents_)) { return false; } diff --git a/util/linux/ptrace_client.cc b/util/linux/ptrace_client.cc index 34fcbc3a..e8afaa4e 100644 --- a/util/linux/ptrace_client.cc +++ b/util/linux/ptrace_client.cc @@ -23,6 +23,7 @@ #include "base/strings/string_number_conversions.h" #include "util/file/file_io.h" #include "util/linux/ptrace_broker.h" +#include "util/misc/arraysize.h" #include "util/process/process_memory_linux.h" namespace crashpad { @@ -270,7 +271,7 @@ bool PtraceClient::Threads(std::vector<pid_t>* threads) { threads->push_back(pid_); char path[32]; - snprintf(path, arraysize(path), "/proc/%d/task", pid_); + snprintf(path, ArraySize(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 089f6815..f2f8f548 100644 --- a/util/mac/checked_mach_address_range_test.cc +++ b/util/mac/checked_mach_address_range_test.cc @@ -19,10 +19,10 @@ #include <limits> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -116,7 +116,7 @@ TEST(CheckedMachAddressRange, IsValid) { {0xffffffffffffffff, 1, kInvalid}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 12ed8320..4a6402dc 100644 --- a/util/mac/launchd_test.mm +++ b/util/mac/launchd_test.mm @@ -23,8 +23,8 @@ #include <limits> #include "base/mac/scoped_launch_data.h" -#include "base/macros.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" #include "util/stdlib/objc.h" namespace crashpad { @@ -58,7 +58,7 @@ TEST(Launchd, CFPropertyToLaunchData_Integer) { @0xfedcba9876543210, }; - for (size_t index = 0; index < arraysize(integer_nses); ++index) { + for (size_t index = 0; index < ArraySize(integer_nses); ++index) { NSNumber* integer_ns = integer_nses[index]; launch_data.reset(CFPropertyToLaunchData(integer_ns)); ASSERT_TRUE(launch_data.get()); @@ -88,7 +88,7 @@ TEST(Launchd, CFPropertyToLaunchData_FloatingPoint) { [NSNumber numberWithDouble:std::numeric_limits<double>::signaling_NaN()], }; - for (size_t index = 0; index < arraysize(double_nses); ++index) { + for (size_t index = 0; index < ArraySize(double_nses); ++index) { NSNumber* double_ns = double_nses[index]; launch_data.reset(CFPropertyToLaunchData(double_ns)); ASSERT_TRUE(launch_data.get()); @@ -114,7 +114,7 @@ TEST(Launchd, CFPropertyToLaunchData_Boolean) { @YES, }; - for (size_t index = 0; index < arraysize(bool_nses); ++index) { + for (size_t index = 0; index < ArraySize(bool_nses); ++index) { NSNumber* bool_ns = bool_nses[index]; launch_data.reset(CFPropertyToLaunchData(bool_ns)); ASSERT_TRUE(launch_data.get()); @@ -138,7 +138,7 @@ TEST(Launchd, CFPropertyToLaunchData_String) { @"Üñîçø∂é", }; - for (size_t index = 0; index < arraysize(string_nses); ++index) { + for (size_t index = 0; index < ArraySize(string_nses); ++index) { NSString* string_ns = string_nses[index]; launch_data.reset(CFPropertyToLaunchData(string_ns)); ASSERT_TRUE(launch_data.get()); diff --git a/util/mac/xattr.cc b/util/mac/xattr.cc index 75d7938d..c63fc87c 100644 --- a/util/mac/xattr.cc +++ b/util/mac/xattr.cc @@ -20,7 +20,6 @@ #include <sys/xattr.h> #include "base/logging.h" -#include "base/macros.h" #include "base/numerics/safe_conversions.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" diff --git a/util/mach/child_port_handshake.cc b/util/mach/child_port_handshake.cc index 750d3cbe..721e560e 100644 --- a/util/mach/child_port_handshake.cc +++ b/util/mach/child_port_handshake.cc @@ -38,6 +38,7 @@ #include "util/mach/mach_extensions.h" #include "util/mach/mach_message.h" #include "util/mach/mach_message_server.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/misc/random_string.h" @@ -158,7 +159,7 @@ mach_port_t ChildPortHandshakeServer::RunServer( 0, nullptr); int rv = HANDLE_EINTR( - kevent(kq.get(), changelist, arraysize(changelist), nullptr, 0, nullptr)); + kevent(kq.get(), changelist, ArraySize(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 a3223028..678d3b29 100644 --- a/util/mach/child_port_server.cc +++ b/util/mach/child_port_server.cc @@ -17,6 +17,7 @@ #include "base/logging.h" #include "util/mach/child_portServer.h" #include "util/mach/mach_message.h" +#include "util/misc/arraysize.h" namespace { @@ -90,7 +91,7 @@ std::set<mach_msg_id_t> ChildPortServer::MachMessageServerRequestIDs() { static constexpr mach_msg_id_t request_ids[] = {kMachMessageIDChildPortCheckIn}; return std::set<mach_msg_id_t>(&request_ids[0], - &request_ids[arraysize(request_ids)]); + &request_ids[ArraySize(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 d45eca0b..c2ed5d79 100644 --- a/util/mach/composite_mach_message_server_test.cc +++ b/util/mach/composite_mach_message_server_test.cc @@ -20,6 +20,7 @@ #include "gtest/gtest.h" #include "test/gtest_death.h" #include "util/mach/mach_message.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -196,7 +197,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { TestMachMessageHandler handlers[3]; std::set<mach_msg_id_t> expect_request_ids; - for (size_t index = 0; index < arraysize(kRequestIDs0); ++index) { + for (size_t index = 0; index < ArraySize(kRequestIDs0); ++index) { const mach_msg_id_t request_id = kRequestIDs0[index]; handlers[0].AddRequestID(request_id); expect_request_ids.insert(request_id); @@ -205,7 +206,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { handlers[0].SetReplySize(sizeof(mig_reply_error_t)); handlers[0].SetReturnCodes(true, kReturnCode0, false); - for (size_t index = 0; index < arraysize(kRequestIDs1); ++index) { + for (size_t index = 0; index < ArraySize(kRequestIDs1); ++index) { const mach_msg_id_t request_id = kRequestIDs1[index]; handlers[1].AddRequestID(request_id); expect_request_ids.insert(request_id); @@ -214,7 +215,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { handlers[1].SetReplySize(200); handlers[1].SetReturnCodes(false, kReturnCode1, true); - for (size_t index = 0; index < arraysize(kRequestIDs2); ++index) { + for (size_t index = 0; index < ArraySize(kRequestIDs2); ++index) { const mach_msg_id_t request_id = kRequestIDs2[index]; handlers[2].AddRequestID(request_id); expect_request_ids.insert(request_id); @@ -252,7 +253,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { // Send messages with known request IDs. - for (size_t index = 0; index < arraysize(kRequestIDs0); ++index) { + for (size_t index = 0; index < ArraySize(kRequestIDs0); ++index) { request.header.msgh_id = kRequestIDs0[index]; SCOPED_TRACE(base::StringPrintf( "handler 0, index %zu, id %d", index, request.header.msgh_id)); @@ -263,7 +264,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { EXPECT_FALSE(destroy_complex_request); } - for (size_t index = 0; index < arraysize(kRequestIDs1); ++index) { + for (size_t index = 0; index < ArraySize(kRequestIDs1); ++index) { request.header.msgh_id = kRequestIDs1[index]; SCOPED_TRACE(base::StringPrintf( "handler 1, index %zu, id %d", index, request.header.msgh_id)); @@ -274,7 +275,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { EXPECT_TRUE(destroy_complex_request); } - for (size_t index = 0; index < arraysize(kRequestIDs2); ++index) { + for (size_t index = 0; index < ArraySize(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 b7288563..7d1d00da 100644 --- a/util/mach/exc_client_variants_test.cc +++ b/util/mach/exc_client_variants_test.cc @@ -29,6 +29,7 @@ #include "util/mach/mach_extensions.h" #include "util/mach/mach_message.h" #include "util/mach/mach_message_server.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -181,11 +182,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 < arraysize(old_state); ++index) { + for (size_t index = 0; index < ArraySize(old_state); ++index) { old_state[index] = index; } old_state_p = reinterpret_cast<thread_state_t>(&old_state); - old_state_count = arraysize(old_state); + old_state_count = ArraySize(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 @@ -202,7 +203,7 @@ class TestExcClientVariants : public MachMultiprocess, task, exception, code, - arraysize(code), + ArraySize(code), flavor_p, old_state_p, old_state_count, @@ -273,7 +274,7 @@ TEST(ExcClientVariants, UniversalExceptionRaise) { kMachExceptionCodes | EXCEPTION_STATE_IDENTITY, }; - for (size_t index = 0; index < arraysize(kBehaviors); ++index) { + for (size_t index = 0; index < ArraySize(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 e7174ac7..f7b0b3d6 100644 --- a/util/mach/exc_server_variants.cc +++ b/util/mach/exc_server_variants.cc @@ -29,6 +29,7 @@ #include "util/mach/mach_exc.h" #include "util/mach/mach_excServer.h" #include "util/mach/mach_message.h" +#include "util/misc/arraysize.h" namespace crashpad { @@ -242,7 +243,7 @@ class ExcServer : public MachMessageServer::Interface { Traits::kMachMessageIDExceptionRaiseStateIdentity, }; return std::set<mach_msg_id_t>(&request_ids[0], - &request_ids[arraysize(request_ids)]); + &request_ids[ArraySize(request_ids)]); } mach_msg_size_t MachMessageServerRequestSize() override { @@ -319,7 +320,7 @@ bool ExcServer<Traits>::MachMessageServerFunction( using Reply = typename Traits::ExceptionRaiseStateReply; Reply* out_reply = reinterpret_cast<Reply*>(out_header); out_reply->flavor = in_request_1->flavor; - out_reply->new_stateCnt = arraysize(out_reply->new_state); + out_reply->new_stateCnt = ArraySize(out_reply->new_state); out_reply->RetCode = interface_->CatchExceptionRaiseState(in_header->msgh_local_port, in_request->exception, @@ -362,7 +363,7 @@ bool ExcServer<Traits>::MachMessageServerFunction( using Reply = typename Traits::ExceptionRaiseStateIdentityReply; Reply* out_reply = reinterpret_cast<Reply*>(out_header); out_reply->flavor = in_request_1->flavor; - out_reply->new_stateCnt = arraysize(out_reply->new_state); + out_reply->new_stateCnt = ArraySize(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 5e67bfe3..b50ded14 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -29,6 +29,7 @@ #include "util/mach/exception_behaviors.h" #include "util/mach/exception_types.h" #include "util/mach/mach_message.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -228,7 +229,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, arraysize(new_state)); + EXPECT_EQ(new_stateCnt, ArraySize(new_state)); } mach_msg_header_t Head; @@ -659,7 +660,7 @@ TEST(ExcServerVariants, MockExceptionRaiseState) { AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(arraysize(reply.new_state)), + IsThreadStateAndCount(ArraySize(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -708,7 +709,7 @@ TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) { AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(arraysize(reply.new_state)), + IsThreadStateAndCount(ArraySize(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -802,7 +803,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseState) { kTestMachExceptionCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(arraysize(reply.new_state)), + IsThreadStateAndCount(ArraySize(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -852,7 +853,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) { kTestMachExceptionCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(arraysize(reply.new_state)), + IsThreadStateAndCount(ArraySize(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -906,7 +907,7 @@ TEST(ExcServerVariants, MockUnknownID) { 2508, }; - for (size_t index = 0; index < arraysize(unknown_ids); ++index) { + for (size_t index = 0; index < ArraySize(unknown_ids); ++index) { mach_msg_id_t id = unknown_ids[index]; SCOPED_TRACE(base::StringPrintf("unknown id %d", id)); @@ -1179,7 +1180,7 @@ TEST(ExcServerVariants, ThreadStates) { #endif }; - for (size_t index = 0; index < arraysize(test_data); ++index) { + for (size_t index = 0; index < ArraySize(test_data); ++index) { const auto& test = test_data[index]; SCOPED_TRACE( base::StringPrintf("index %zu, flavor %d", index, test.flavor)); @@ -1252,7 +1253,7 @@ TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) { KERN_SUCCESS}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(kTestData); ++index) { const auto& test_data = kTestData[index]; SCOPED_TRACE( base::StringPrintf("index %zu, behavior %d, set_thread_state %s", @@ -1271,8 +1272,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 = arraysize(old_state); - mach_msg_type_number_t new_state_count = arraysize(new_state); + constexpr mach_msg_type_number_t old_state_count = ArraySize(old_state); + mach_msg_type_number_t new_state_count = ArraySize(new_state); // EXCEPTION_DEFAULT (with or without MACH_EXCEPTION_CODES) is not // state-carrying. new_state and new_state_count should be untouched. @@ -1281,8 +1282,8 @@ TEST(ExcServerVariants, ExcServerCopyState) { old_state_count, new_state, &new_state_count); - EXPECT_EQ(new_state_count, arraysize(new_state)); - for (size_t i = 0; i < arraysize(new_state); ++i) { + EXPECT_EQ(new_state_count, ArraySize(new_state)); + for (size_t i = 0; i < ArraySize(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } @@ -1291,8 +1292,8 @@ TEST(ExcServerVariants, ExcServerCopyState) { old_state_count, new_state, &new_state_count); - EXPECT_EQ(new_state_count, arraysize(new_state)); - for (size_t i = 0; i < arraysize(new_state); ++i) { + EXPECT_EQ(new_state_count, ArraySize(new_state)); + for (size_t i = 0; i < ArraySize(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } @@ -1304,7 +1305,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 < arraysize(new_state); ++i) { + for (size_t i = copy_limit; i < ArraySize(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } @@ -1320,23 +1321,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 < arraysize(new_state); ++i) { + for (size_t i = copy_limit; i < ArraySize(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 = arraysize(new_state); + new_state_count = ArraySize(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 < arraysize(old_state); ++i) { + for (size_t i = 0; i < ArraySize(old_state); ++i) { EXPECT_EQ(new_state[i], old_state[i]) << "i " << i; } - for (size_t i = arraysize(old_state); i < arraysize(new_state); ++i) { + for (size_t i = ArraySize(old_state); i < ArraySize(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 d45110d9..fd74d22c 100644 --- a/util/mach/exception_behaviors_test.cc +++ b/util/mach/exception_behaviors_test.cc @@ -16,10 +16,10 @@ #include <sys/types.h> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/mach/mach_extensions.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -53,7 +53,7 @@ TEST(ExceptionBehaviors, ExceptionBehaviors) { EXCEPTION_STATE_IDENTITY}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 c24428a2..030c7f30 100644 --- a/util/mach/exception_types_test.cc +++ b/util/mach/exception_types_test.cc @@ -20,11 +20,11 @@ #include <sys/types.h> #include <unistd.h> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/mac/mac_util.h" #include "util/mach/mach_extensions.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -67,7 +67,7 @@ TEST(ExceptionTypes, ExcCrashRecoverOriginalException) { {0, 0, 0, 0}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(kTestData); ++index) { const auto& test_data = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %zu, code_0 0x%llx", index, test_data.code_0)); @@ -84,7 +84,7 @@ TEST(ExceptionTypes, ExcCrashRecoverOriginalException) { // Now make sure that ExcCrashRecoverOriginalException() properly ignores // optional arguments. - static_assert(arraysize(kTestData) >= 1, "must have something to test"); + static_assert(ArraySize(kTestData) >= 1, "must have something to test"); const auto& test_data = kTestData[0]; EXPECT_EQ( ExcCrashRecoverOriginalException(test_data.code_0, nullptr, nullptr), @@ -238,7 +238,7 @@ TEST(ExceptionTypes, ExceptionCodeForMetrics) { {0x00010000, 0x00010000, static_cast<int32_t>(0xffffffff)}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 16ba8f20..724d84e2 100644 --- a/util/mach/mach_message_server_test.cc +++ b/util/mach/mach_message_server_test.cc @@ -29,6 +29,7 @@ #include "util/file/file_io.h" #include "util/mach/mach_extensions.h" #include "util/mach/mach_message.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -281,7 +282,7 @@ class TestMachMessageServer : public MachMessageServer::Interface, std::set<mach_msg_id_t> MachMessageServerRequestIDs() override { static constexpr mach_msg_id_t request_ids[] = {kRequestMessageID}; return std::set<mach_msg_id_t>(&request_ids[0], - &request_ids[arraysize(request_ids)]); + &request_ids[ArraySize(request_ids)]); } mach_msg_size_t MachMessageServerRequestSize() override { diff --git a/util/mach/mach_message_test.cc b/util/mach/mach_message_test.cc index d88ca855..b00b187a 100644 --- a/util/mach/mach_message_test.cc +++ b/util/mach/mach_message_test.cc @@ -17,6 +17,7 @@ #include <unistd.h> #include "base/mac/scoped_mach_port.h" +#include "base/macros.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" #include "util/mach/mach_extensions.h" diff --git a/util/mach/notify_server.cc b/util/mach/notify_server.cc index 711529b1..5d0b3c0c 100644 --- a/util/mach/notify_server.cc +++ b/util/mach/notify_server.cc @@ -17,6 +17,7 @@ #include "base/logging.h" #include "util/mach/mach_message.h" #include "util/mach/notifyServer.h" +#include "util/misc/arraysize.h" namespace { @@ -227,7 +228,7 @@ std::set<mach_msg_id_t> NotifyServer::MachMessageServerRequestIDs() { MACH_NOTIFY_DEAD_NAME, }; return std::set<mach_msg_id_t>(&request_ids[0], - &request_ids[arraysize(request_ids)]); + &request_ids[ArraySize(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 98a2d203..fa6eefb3 100644 --- a/util/mach/symbolic_constants_mach.cc +++ b/util/mach/symbolic_constants_mach.cc @@ -17,10 +17,10 @@ #include <string.h> #include <sys/types.h> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "util/mach/exception_behaviors.h" #include "util/mach/mach_extensions.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/stdlib/string_number_conversion.h" @@ -45,7 +45,7 @@ constexpr const char* kExceptionNames[] = { "GUARD", "CORPSE_NOTIFY", }; -static_assert(arraysize(kExceptionNames) == EXC_TYPES_COUNT, +static_assert(ArraySize(kExceptionNames) == EXC_TYPES_COUNT, "kExceptionNames length"); constexpr char kExcPrefix[] = "EXC_"; @@ -170,8 +170,7 @@ std::string ThreadStateFlavorFullToShort(const base::StringPiece& flavor) { {"_STATE32", "32"}, {"_STATE64", "64"}, }; - for (size_t suffix_index = 0; - suffix_index < arraysize(kStateSuffixes); + for (size_t suffix_index = 0; suffix_index < ArraySize(kStateSuffixes); ++suffix_index) { const char* suffix = kStateSuffixes[suffix_index].orig; size_t suffix_len = strlen(suffix); @@ -195,7 +194,7 @@ namespace crashpad { std::string ExceptionToString(exception_type_t exception, SymbolicConstantToStringOptions options) { const char* exception_name = - implicit_cast<size_t>(exception) < arraysize(kExceptionNames) + implicit_cast<size_t>(exception) < ArraySize(kExceptionNames) ? kExceptionNames[exception] : nullptr; if (!exception_name) { @@ -221,7 +220,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<exception_type_t>(arraysize(kExceptionNames)); + index < implicit_cast<exception_type_t>(ArraySize(kExceptionNames)); ++index) { const char* exception_name = kExceptionNames[index]; if (!exception_name) { @@ -251,8 +250,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 < arraysize(kExceptionNames); + for (size_t exception = 0; exception < ArraySize(kExceptionNames); ++exception) { const char* exception_name = kExceptionNames[exception]; exception_mask_t exception_mask_value = 1 << exception; @@ -326,7 +324,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<exception_type_t>(arraysize(kExceptionNames)); + index < implicit_cast<exception_type_t>(ArraySize(kExceptionNames)); ++index) { const char* exception_name = kExceptionNames[index]; if (!exception_name) { @@ -365,7 +363,7 @@ std::string ExceptionBehaviorToString(exception_behavior_t behavior, const exception_behavior_t basic_behavior = ExceptionBehaviorBasic(behavior); const char* behavior_name = - implicit_cast<size_t>(basic_behavior) < arraysize(kBehaviorNames) + implicit_cast<size_t>(basic_behavior) < ArraySize(kBehaviorNames) ? kBehaviorNames[basic_behavior] : nullptr; if (!behavior_name) { @@ -432,7 +430,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<exception_behavior_t>(arraysize(kBehaviorNames)); + index < implicit_cast<exception_behavior_t>(ArraySize(kBehaviorNames)); ++index) { const char* behavior_name = kBehaviorNames[index]; if (!behavior_name) { @@ -468,13 +466,13 @@ bool StringToExceptionBehavior(const base::StringPiece& string, std::string ThreadStateFlavorToString(thread_state_flavor_t flavor, SymbolicConstantToStringOptions options) { const char* flavor_name = - implicit_cast<size_t>(flavor) < arraysize(kFlavorNames) + implicit_cast<size_t>(flavor) < ArraySize(kFlavorNames) ? kFlavorNames[flavor] : nullptr; if (!flavor_name) { for (size_t generic_flavor_index = 0; - generic_flavor_index < arraysize(kGenericFlavorNames); + generic_flavor_index < ArraySize(kGenericFlavorNames); ++generic_flavor_index) { if (flavor == kGenericFlavorNames[generic_flavor_index].flavor) { flavor_name = kGenericFlavorNames[generic_flavor_index].name; @@ -501,7 +499,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<thread_state_flavor_t>(arraysize(kFlavorNames)); + index < implicit_cast<thread_state_flavor_t>(ArraySize(kFlavorNames)); ++index) { const char* flavor_name = kFlavorNames[index]; if (!flavor_name) { @@ -521,7 +519,7 @@ bool StringToThreadStateFlavor(const base::StringPiece& string, } for (size_t generic_flavor_index = 0; - generic_flavor_index < arraysize(kGenericFlavorNames); + generic_flavor_index < ArraySize(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 3bf5abb1..4856f0ad 100644 --- a/util/mach/symbolic_constants_mach_test.cc +++ b/util/mach/symbolic_constants_mach_test.cc @@ -18,14 +18,15 @@ #include <string.h> #include <sys/types.h> -#include "base/macros.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/mach/mach_extensions.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" -#define NUL_TEST_DATA(string) { string, arraysize(string) - 1 } +#define NUL_TEST_DATA(string) \ + { string, ArraySize(string) - 1 } namespace crashpad { namespace test { @@ -159,7 +160,7 @@ void TestExceptionToString(exception_type_t value, } TEST(SymbolicConstantsMach, ExceptionToString) { - for (size_t index = 0; index < arraysize(kExceptionTestData); ++index) { + for (size_t index = 0; index < ArraySize(kExceptionTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestExceptionToString(kExceptionTestData[index].exception, kExceptionTestData[index].full_name, @@ -187,12 +188,11 @@ void TestStringToException(const base::StringPiece& string, } TEST(SymbolicConstantsMach, StringToException) { - for (size_t option_index = 0; - option_index < arraysize(kNormalOptions); + for (size_t option_index = 0; option_index < ArraySize(kNormalOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kNormalOptions[option_index]; - for (size_t index = 0; index < arraysize(kExceptionTestData); ++index) { + for (size_t index = 0; index < ArraySize(kExceptionTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); exception_type_t exception = kExceptionTestData[index].exception; { @@ -230,7 +230,7 @@ TEST(SymbolicConstantsMach, StringToException) { "", }; - for (size_t index = 0; index < arraysize(kNegativeTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToException(kNegativeTestData[index], options, false, 0); } @@ -251,7 +251,7 @@ TEST(SymbolicConstantsMach, StringToException) { NUL_TEST_DATA("1\0002"), }; - for (size_t index = 0; index < arraysize(kNULTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); @@ -334,7 +334,7 @@ void TestExceptionMaskToString(exception_mask_t value, } TEST(SymbolicConstantsMach, ExceptionMaskToString) { - for (size_t index = 0; index < arraysize(kExceptionMaskTestData); ++index) { + for (size_t index = 0; index < ArraySize(kExceptionMaskTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestExceptionMaskToString(kExceptionMaskTestData[index].exception_mask, kExceptionMaskTestData[index].full_name, @@ -389,12 +389,11 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { kAllowFullName | kAllowShortName | kAllowNumber | kAllowOr, }; - for (size_t option_index = 0; - option_index < arraysize(kOptions); + for (size_t option_index = 0; option_index < ArraySize(kOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kOptions[option_index]; - for (size_t index = 0; index < arraysize(kExceptionMaskTestData); ++index) { + for (size_t index = 0; index < ArraySize(kExceptionMaskTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); exception_mask_t exception_mask = kExceptionMaskTestData[index].exception_mask; @@ -445,7 +444,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { "", }; - for (size_t index = 0; index < arraysize(kNegativeTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionMask(kNegativeTestData[index], options, false, 0); } @@ -471,7 +470,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { NUL_TEST_DATA("ARITHMETIC|\0EMULATION"), }; - for (size_t index = 0; index < arraysize(kNULTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); @@ -506,7 +505,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { EXC_MASK_SYSCALL | 0x100}, }; - for (size_t index = 0; index < arraysize(kNonCanonicalTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNonCanonicalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionMask(kNonCanonicalTestData[index].string, kNonCanonicalTestData[index].options, @@ -577,8 +576,7 @@ void TestExceptionBehaviorToString(exception_behavior_t value, } TEST(SymbolicConstantsMach, ExceptionBehaviorToString) { - for (size_t index = 0; - index < arraysize(kExceptionBehaviorTestData); + for (size_t index = 0; index < ArraySize(kExceptionBehaviorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestExceptionBehaviorToString(kExceptionBehaviorTestData[index].behavior, @@ -608,13 +606,11 @@ void TestStringToExceptionBehavior(const base::StringPiece& string, } TEST(SymbolicConstantsMach, StringToExceptionBehavior) { - for (size_t option_index = 0; - option_index < arraysize(kNormalOptions); + for (size_t option_index = 0; option_index < ArraySize(kNormalOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kNormalOptions[option_index]; - for (size_t index = 0; - index < arraysize(kExceptionBehaviorTestData); + for (size_t index = 0; index < ArraySize(kExceptionBehaviorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); exception_behavior_t behavior = @@ -660,7 +656,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { "", }; - for (size_t index = 0; index < arraysize(kNegativeTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionBehavior( kNegativeTestData[index], options, false, 0); @@ -686,7 +682,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { NUL_TEST_DATA("STATE_IDENTITY|\0MACH"), }; - for (size_t index = 0; index < arraysize(kNULTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); @@ -723,7 +719,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { implicit_cast<exception_behavior_t>(MACH_EXCEPTION_CODES | 0x2)}, }; - for (size_t index = 0; index < arraysize(kNonCanonicalTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNonCanonicalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionBehavior(kNonCanonicalTestData[index].string, kNonCanonicalTestData[index].options, @@ -840,8 +836,7 @@ void TestThreadStateFlavorToString(exception_type_t value, } TEST(SymbolicConstantsMach, ThreadStateFlavorToString) { - for (size_t index = 0; - index < arraysize(kThreadStateFlavorTestData); + for (size_t index = 0; index < ArraySize(kThreadStateFlavorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestThreadStateFlavorToString(kThreadStateFlavorTestData[index].flavor, @@ -883,13 +878,11 @@ void TestStringToThreadStateFlavor(const base::StringPiece& string, } TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { - for (size_t option_index = 0; - option_index < arraysize(kNormalOptions); + for (size_t option_index = 0; option_index < ArraySize(kNormalOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kNormalOptions[option_index]; - for (size_t index = 0; - index < arraysize(kThreadStateFlavorTestData); + for (size_t index = 0; index < ArraySize(kThreadStateFlavorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); thread_state_flavor_t flavor = kThreadStateFlavorTestData[index].flavor; @@ -959,7 +952,7 @@ TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { #endif }; - for (size_t index = 0; index < arraysize(kNegativeTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToThreadStateFlavor( kNegativeTestData[index], options, false, 0); @@ -1025,7 +1018,7 @@ TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { #endif }; - for (size_t index = 0; index < arraysize(kNULTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 new file mode 100644 index 00000000..d476edbc --- /dev/null +++ b/util/misc/arraysize.h @@ -0,0 +1,39 @@ +// 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_UTIL_MISC_ARRAYSIZE_H_ +#define CRASHPAD_UTIL_MISC_ARRAYSIZE_H_ + +#include <sys/types.h> // For size_t. + +#include <type_traits> + +//! \file + +namespace crashpad { +namespace internal { + +//! \brief A helper to implement ArraySize. +template <typename ArrayType> +constexpr size_t ArraySizeHelper() noexcept { + return std::extent<typename std::remove_reference<ArrayType>::type>::value; +} + +} // namespace internal +} // namespace crashpad + +//! \brief A way of computing an array’s size. +#define ArraySize(array) crashpad::internal::ArraySizeHelper<decltype(array)>() + +#endif // CRASHPAD_UTIL_MISC_ARRAYSIZE_H_ diff --git a/util/misc/arraysize_unsafe_test.cc b/util/misc/arraysize_test.cc similarity index 68% rename from util/misc/arraysize_unsafe_test.cc rename to util/misc/arraysize_test.cc index a6660aee..ad8da097 100644 --- a/util/misc/arraysize_unsafe_test.cc +++ b/util/misc/arraysize_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "util/misc/arraysize_unsafe.h" +#include "util/misc/arraysize.h" #include "base/compiler_specific.h" #include "gtest/gtest.h" @@ -21,37 +21,37 @@ namespace crashpad { namespace test { namespace { -TEST(ArraySizeUnsafe, ArraySizeUnsafe) { +TEST(ArraySize, ArraySize) { char c1[1]; - static_assert(ARRAYSIZE_UNSAFE(c1) == 1, "c1"); + static_assert(ArraySize(c1) == 1, "c1"); ALLOW_UNUSED_LOCAL(c1); char c2[2]; - static_assert(ARRAYSIZE_UNSAFE(c2) == 2, "c2"); + static_assert(ArraySize(c2) == 2, "c2"); ALLOW_UNUSED_LOCAL(c2); char c4[4]; - static_assert(ARRAYSIZE_UNSAFE(c4) == 4, "c4"); + static_assert(ArraySize(c4) == 4, "c4"); ALLOW_UNUSED_LOCAL(c4); int i1[1]; - static_assert(ARRAYSIZE_UNSAFE(i1) == 1, "i1"); + static_assert(ArraySize(i1) == 1, "i1"); ALLOW_UNUSED_LOCAL(i1); int i2[2]; - static_assert(ARRAYSIZE_UNSAFE(i2) == 2, "i2"); + static_assert(ArraySize(i2) == 2, "i2"); ALLOW_UNUSED_LOCAL(i2); int i4[4]; - static_assert(ARRAYSIZE_UNSAFE(i4) == 4, "i4"); + static_assert(ArraySize(i4) == 4, "i4"); ALLOW_UNUSED_LOCAL(i4); long l8[8]; - static_assert(ARRAYSIZE_UNSAFE(l8) == 8, "l8"); + static_assert(ArraySize(l8) == 8, "l8"); ALLOW_UNUSED_LOCAL(l8); int l9[9]; - static_assert(ARRAYSIZE_UNSAFE(l9) == 9, "l9"); + static_assert(ArraySize(l9) == 9, "l9"); ALLOW_UNUSED_LOCAL(l9); struct S { @@ -62,11 +62,11 @@ TEST(ArraySizeUnsafe, ArraySizeUnsafe) { }; S s1[1]; - static_assert(ARRAYSIZE_UNSAFE(s1) == 1, "s1"); + static_assert(ArraySize(s1) == 1, "s1"); ALLOW_UNUSED_LOCAL(s1); S s10[10]; - static_assert(ARRAYSIZE_UNSAFE(s10) == 10, "s10"); + static_assert(ArraySize(s10) == 10, "s10"); ALLOW_UNUSED_LOCAL(s10); } diff --git a/util/misc/arraysize_unsafe.h b/util/misc/arraysize_unsafe.h deleted file mode 100644 index e53c70b8..00000000 --- a/util/misc/arraysize_unsafe.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2016 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_MISC_ARRAYSIZE_UNSAFE_H_ -#define CRASHPAD_UTIL_MISC_ARRAYSIZE_UNSAFE_H_ - -//! \file - -//! \brief Not the safest way of computing an array’s size… -//! -//! `#%include "base/macros.h"` and use its `arraysize()` instead. This macro -//! should only be used in rare situations where `arraysize()` does not -//! function. -#define ARRAYSIZE_UNSAFE(array) (sizeof(array) / sizeof(array[0])) - -#endif // CRASHPAD_UTIL_MISC_ARRAYSIZE_UNSAFE_H_ diff --git a/util/misc/capture_context_test_util_win.cc b/util/misc/capture_context_test_util_win.cc index 092449ef..d8abd377 100644 --- a/util/misc/capture_context_test_util_win.cc +++ b/util/misc/capture_context_test_util_win.cc @@ -15,8 +15,8 @@ #include "util/misc/capture_context_test_util.h" #include "util/win/context_wrappers.h" -#include "base/macros.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -59,7 +59,7 @@ void SanityCheckContext(const NativeCPUContext& context) { #if defined(ARCH_CPU_X86) // fxsave doesn’t write these bytes. - for (size_t i = 464; i < arraysize(context.ExtendedRegisters); ++i) { + for (size_t i = 464; i < ArraySize(context.ExtendedRegisters); ++i) { SCOPED_TRACE(i); EXPECT_EQ(context.ExtendedRegisters[i], 0); } @@ -69,7 +69,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 < arraysize(context.FltSave.Reserved4); ++i) { + for (size_t i = 0; i < ArraySize(context.FltSave.Reserved4); ++i) { SCOPED_TRACE(i); EXPECT_EQ(context.FltSave.Reserved4[i], 0); } @@ -81,7 +81,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 < arraysize(context.VectorRegister); ++i) { + for (size_t i = 0; i < ArraySize(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 95330eb2..ca4bf009 100644 --- a/util/misc/clock_test.cc +++ b/util/misc/clock_test.cc @@ -20,9 +20,9 @@ #include "base/format_macros.h" #include "base/logging.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -83,7 +83,7 @@ TEST(Clock, SleepNanoseconds) { static_cast<uint64_t>(5E7), // 50 milliseconds }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 4c402fe9..aa5c786e 100644 --- a/util/misc/paths_win.cc +++ b/util/misc/paths_win.cc @@ -17,18 +17,19 @@ #include <windows.h> #include "base/logging.h" +#include "util/misc/arraysize.h" namespace crashpad { // static bool Paths::Executable(base::FilePath* path) { wchar_t executable_path[_MAX_PATH]; - unsigned int len = - GetModuleFileName(nullptr, executable_path, arraysize(executable_path)); + unsigned int len = GetModuleFileName( + nullptr, executable_path, static_cast<DWORD>(ArraySize(executable_path))); if (len == 0) { PLOG(ERROR) << "GetModuleFileName"; return false; - } else if (len >= arraysize(executable_path)) { + } else if (len >= ArraySize(executable_path)) { LOG(ERROR) << "GetModuleFileName"; return false; } diff --git a/util/misc/random_string_test.cc b/util/misc/random_string_test.cc index b0866c06..5d9fad62 100644 --- a/util/misc/random_string_test.cc +++ b/util/misc/random_string_test.cc @@ -18,8 +18,8 @@ #include <set> -#include "base/macros.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -33,7 +33,7 @@ TEST(RandomString, RandomString) { const std::string allowed_characters("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); size_t character_counts[26] = {}; - ASSERT_EQ(allowed_characters.size(), arraysize(character_counts)); + ASSERT_EQ(allowed_characters.size(), ArraySize(character_counts)); std::set<std::string> 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 < arraysize(character_counts); + character_index < ArraySize(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 c05c5c1b..b8519198 100644 --- a/util/misc/uuid_test.cc +++ b/util/misc/uuid_test.cc @@ -20,10 +20,10 @@ #include <string> #include "base/format_macros.h" -#include "base/macros.h" #include "base/scoped_generic.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -95,12 +95,12 @@ TEST(UUID, UUID) { ++uuid.data_3; EXPECT_NE(uuid, uuid_2); --uuid.data_3; - for (size_t index = 0; index < arraysize(uuid.data_4); ++index) { + for (size_t index = 0; index < ArraySize(uuid.data_4); ++index) { ++uuid.data_4[index]; EXPECT_NE(uuid, uuid_2); --uuid.data_4[index]; } - for (size_t index = 0; index < arraysize(uuid.data_5); ++index) { + for (size_t index = 0; index < ArraySize(uuid.data_5); ++index) { ++uuid.data_5[index]; EXPECT_NE(uuid, uuid_2); --uuid.data_5[index]; @@ -190,7 +190,7 @@ TEST(UUID, FromString) { uuid_zero.InitializeToZero(); const std::string empty_uuid = uuid_zero.ToString(); - for (size_t index = 0; index < arraysize(kCases); ++index) { + for (size_t index = 0; index < ArraySize(kCases); ++index) { const TestCase& test_case = kCases[index]; SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ": %s", index, test_case.uuid_string)); @@ -226,7 +226,7 @@ TEST(UUID, FromString) { }; // clang-format on EXPECT_TRUE(uuid.InitializeFromString( - base::StringPiece16(kChar16UUID, arraysize(kChar16UUID)))); + base::StringPiece16(kChar16UUID, ArraySize(kChar16UUID)))); EXPECT_EQ(uuid.ToString(), "f32e5bdc-2681-4c73-a4e6-333ffd33b333"); #if defined(OS_WIN) diff --git a/util/net/http_transport_socket.cc b/util/net/http_transport_socket.cc index 75ed38fd..b390238f 100644 --- a/util/net/http_transport_socket.cc +++ b/util/net/http_transport_socket.cc @@ -27,6 +27,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "util/file/file_io.h" +#include "util/misc/arraysize.h" #include "util/net/http_body.h" #include "util/net/url.h" #include "util/stdlib/string_number_conversion.h" @@ -365,7 +366,7 @@ bool WriteRequest(Stream* stream, FileOperationResult data_bytes; do { - constexpr size_t kCRLFSize = arraysize(kCRLFTerminator) - 1; + constexpr size_t kCRLFSize = ArraySize(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 f86e4594..06d0b7b2 100644 --- a/util/net/http_transport_win.cc +++ b/util/net/http_transport_win.cc @@ -31,8 +31,9 @@ #include "build/build_config.h" #include "package.h" #include "util/file/file_io.h" -#include "util/numeric/safe_assignment.h" +#include "util/misc/arraysize.h" #include "util/net/http_body.h" +#include "util/numeric/safe_assignment.h" #include "util/win/module_version.h" namespace crashpad { @@ -95,7 +96,7 @@ std::string WinHttpMessage(const char* extra) { error_code, 0, msgbuf, - arraysize(msgbuf), + static_cast<DWORD>(ArraySize(msgbuf)), NULL); 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 e6bd9ecd..f5dc8adc 100644 --- a/util/numeric/checked_address_range_test.cc +++ b/util/numeric/checked_address_range_test.cc @@ -19,10 +19,10 @@ #include <limits> #include "base/format_macros.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -119,7 +119,7 @@ TEST(CheckedAddressRange, IsValid) { {0xffffffffffffffff, 1, kInvalid}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 04f6bb1f..2977b42e 100644 --- a/util/numeric/checked_range_test.cc +++ b/util/numeric/checked_range_test.cc @@ -20,9 +20,9 @@ #include <limits> #include "base/format_macros.h" -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -78,7 +78,7 @@ TEST(CheckedRange, IsValid) { {0xffffffff, 0xffffffff, false}, }; - for (size_t index = 0; index < arraysize(kUnsignedTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 < arraysize(kSignedTestData); ++index) { + for (size_t index = 0; index < ArraySize(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<uint32_t> parent_range(0x2000, 0x1000); ASSERT_TRUE(parent_range.IsValid()); - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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<uint32_t> parent_range(0x2000, 0x1000); ASSERT_TRUE(parent_range.IsValid()); - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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<uint32_t> first_range(0x2000, 0x1000); ASSERT_TRUE(first_range.IsValid()); - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 02c8a767..22f89f52 100644 --- a/util/posix/close_multiple.cc +++ b/util/posix/close_multiple.cc @@ -28,6 +28,7 @@ #include "base/strings/string_number_conversions.h" #include "build/build_config.h" #include "util/file/directory_reader.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #if defined(OS_MACOSX) @@ -152,7 +153,7 @@ void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { int maxfilesperproc; size_t maxfilesperproc_size = sizeof(maxfilesperproc); if (sysctl(oid, - arraysize(oid), + ArraySize(oid), &maxfilesperproc, &maxfilesperproc_size, nullptr, diff --git a/util/posix/close_stdio.cc b/util/posix/close_stdio.cc index cc9cdac8..02bd4a93 100644 --- a/util/posix/close_stdio.cc +++ b/util/posix/close_stdio.cc @@ -20,6 +20,7 @@ #include "base/files/scoped_file.h" #include "base/logging.h" +#include "base/macros.h" #include "base/posix/eintr_wrapper.h" namespace crashpad { diff --git a/util/posix/process_info_mac.cc b/util/posix/process_info_mac.cc index fe9fb654..8b9a6ec0 100644 --- a/util/posix/process_info_mac.cc +++ b/util/posix/process_info_mac.cc @@ -18,6 +18,7 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" +#include "util/misc/arraysize.h" namespace crashpad { @@ -32,7 +33,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, arraysize(mib), &kern_proc_info_, &len, nullptr, 0) != 0) { + if (sysctl(mib, ArraySize(mib), &kern_proc_info_, &len, nullptr, 0) != 0) { PLOG(ERROR) << "sysctl for pid " << pid; return false; } @@ -111,7 +112,7 @@ std::set<gid_t> ProcessInfo::SupplementaryGroups() const { const short ngroups = kern_proc_info_.kp_eproc.e_ucred.cr_ngroups; DCHECK_GE(ngroups, 0); DCHECK_LE(static_cast<size_t>(ngroups), - arraysize(kern_proc_info_.kp_eproc.e_ucred.cr_groups)); + ArraySize(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<gid_t>(&groups[0], &groups[ngroups]); @@ -168,7 +169,7 @@ bool ProcessInfo::Arguments(std::vector<std::string>* argv) const { do { int mib[] = {CTL_KERN, KERN_PROCARGS2, pid}; int rv = - sysctl(mib, arraysize(mib), nullptr, &args_size_estimate, nullptr, 0); + sysctl(mib, ArraySize(mib), nullptr, &args_size_estimate, nullptr, 0); if (rv != 0) { PLOG(ERROR) << "sysctl (size) for pid " << pid; return false; @@ -176,7 +177,7 @@ bool ProcessInfo::Arguments(std::vector<std::string>* argv) const { args_size = args_size_estimate + 1; args.resize(args_size); - rv = sysctl(mib, arraysize(mib), &args[0], &args_size, nullptr, 0); + rv = sysctl(mib, ArraySize(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 7312b849..0a6a1fa1 100644 --- a/util/posix/scoped_mmap_test.cc +++ b/util/posix/scoped_mmap_test.cc @@ -23,6 +23,7 @@ #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/gtest_death.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -150,7 +151,7 @@ TEST(ScopedMmapDeathTest, ResetAddrLen_Shrink) { EXPECT_EQ(mapping.len(), 3 * kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < arraysize(cookies); ++index) { + for (size_t index = 0; index < ArraySize(cookies); ++index) { cookies[index].SetUp(reinterpret_cast<uint64_t*>( mapping.addr_as<uintptr_t>() + index * kPageSize)); } @@ -185,7 +186,7 @@ TEST(ScopedMmap, ResetAddrLen_Grow) { EXPECT_EQ(mapping.len(), kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < arraysize(cookies); ++index) { + for (size_t index = 0; index < ArraySize(cookies); ++index) { cookies[index].SetUp(reinterpret_cast<uint64_t*>( reinterpret_cast<uintptr_t>(pages) + index * kPageSize)); } @@ -196,7 +197,7 @@ TEST(ScopedMmap, ResetAddrLen_Grow) { EXPECT_EQ(mapping.addr(), pages); EXPECT_EQ(mapping.len(), 3 * kPageSize); - for (size_t index = 0; index < arraysize(cookies); ++index) { + for (size_t index = 0; index < ArraySize(cookies); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); EXPECT_EQ(cookies[index].Observed(), cookies[index].Expected()); } @@ -217,7 +218,7 @@ TEST(ScopedMmapDeathTest, ResetAddrLen_MoveDownAndGrow) { EXPECT_EQ(mapping.len(), kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < arraysize(cookies); ++index) { + for (size_t index = 0; index < ArraySize(cookies); ++index) { cookies[index].SetUp(reinterpret_cast<uint64_t*>( reinterpret_cast<uintptr_t>(pages) + index * kPageSize)); } @@ -248,7 +249,7 @@ TEST(ScopedMmapDeathTest, ResetAddrLen_MoveUpAndShrink) { EXPECT_EQ(mapping.len(), 2 * kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < arraysize(cookies); ++index) { + for (size_t index = 0; index < ArraySize(cookies); ++index) { cookies[index].SetUp(reinterpret_cast<uint64_t*>( reinterpret_cast<uintptr_t>(pages) + index * kPageSize)); } diff --git a/util/posix/signals.cc b/util/posix/signals.cc index 63764ab8..69cdfca3 100644 --- a/util/posix/signals.cc +++ b/util/posix/signals.cc @@ -19,6 +19,7 @@ #include <vector> #include "base/logging.h" +#include "util/misc/arraysize.h" namespace crashpad { @@ -118,7 +119,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, arraysize(actions_)); + DCHECK_LT(slot, ArraySize(actions_)); return &actions_[slot]; } @@ -152,7 +153,7 @@ bool Signals::InstallCrashHandlers(Handler handler, int flags, OldActions* old_actions) { return InstallHandlers( - std::vector<int>(kCrashSignals, kCrashSignals + arraysize(kCrashSignals)), + std::vector<int>(kCrashSignals, kCrashSignals + ArraySize(kCrashSignals)), handler, flags, old_actions); @@ -164,7 +165,7 @@ bool Signals::InstallTerminateHandlers(Handler handler, OldActions* old_actions) { return InstallHandlers( std::vector<int>(kTerminateSignals, - kTerminateSignals + arraysize(kTerminateSignals)), + kTerminateSignals + ArraySize(kTerminateSignals)), handler, flags, old_actions); @@ -279,12 +280,12 @@ void Signals::RestoreHandlerAndReraiseSignalOnReturn( // static bool Signals::IsCrashSignal(int sig) { - return IsSignalInSet(sig, kCrashSignals, arraysize(kCrashSignals)); + return IsSignalInSet(sig, kCrashSignals, ArraySize(kCrashSignals)); } // static bool Signals::IsTerminateSignal(int sig) { - return IsSignalInSet(sig, kTerminateSignals, arraysize(kTerminateSignals)); + return IsSignalInSet(sig, kTerminateSignals, ArraySize(kTerminateSignals)); } } // namespace crashpad diff --git a/util/posix/signals_test.cc b/util/posix/signals_test.cc index 75ff5580..b0c84071 100644 --- a/util/posix/signals_test.cc +++ b/util/posix/signals_test.cc @@ -32,6 +32,7 @@ #include "test/errors.h" #include "test/multiprocess.h" #include "test/scoped_temp_dir.h" +#include "util/misc/arraysize.h" #include "util/posix/scoped_mmap.h" namespace crashpad { @@ -340,7 +341,7 @@ TEST(Signals, WillSignalReraiseAutonomously) { {SIGHUP, SEGV_MAPERR, false}, {SIGINT, SI_USER, false}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 8008ffb6..f1fa87f0 100644 --- a/util/posix/symbolic_constants_posix.cc +++ b/util/posix/symbolic_constants_posix.cc @@ -18,9 +18,9 @@ #include <string.h> #include <sys/types.h> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" +#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/stdlib/string_number_conversion.h" @@ -137,9 +137,9 @@ constexpr const char* kSignalNames[] = { }; #if defined(OS_LINUX) || defined(OS_ANDROID) // NSIG is 64 to account for real-time signals. -static_assert(arraysize(kSignalNames) == 32, "kSignalNames length"); +static_assert(ArraySize(kSignalNames) == 32, "kSignalNames length"); #else -static_assert(arraysize(kSignalNames) == NSIG, "kSignalNames length"); +static_assert(ArraySize(kSignalNames) == NSIG, "kSignalNames length"); #endif constexpr char kSigPrefix[] = "SIG"; @@ -151,7 +151,7 @@ namespace crashpad { std::string SignalToString(int signal, SymbolicConstantToStringOptions options) { const char* signal_name = - implicit_cast<size_t>(signal) < arraysize(kSignalNames) + implicit_cast<size_t>(signal) < ArraySize(kSignalNames) ? kSignalNames[signal] : nullptr; if (!signal_name) { @@ -176,8 +176,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<int>(arraysize(kSignalNames)); + for (int index = 0; index < implicit_cast<int>(ArraySize(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 32c1d434..1a6e0b90 100644 --- a/util/posix/symbolic_constants_posix_test.cc +++ b/util/posix/symbolic_constants_posix_test.cc @@ -17,13 +17,14 @@ #include <signal.h> #include <sys/types.h> -#include "base/macros.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" -#define NUL_TEST_DATA(string) { string, arraysize(string) - 1 } +#define NUL_TEST_DATA(string) \ + { string, ArraySize(string) - 1 } namespace crashpad { namespace test { @@ -115,7 +116,7 @@ void TestSignalToString(int value, } TEST(SymbolicConstantsPOSIX, SignalToString) { - for (size_t index = 0; index < arraysize(kSignalTestData); ++index) { + for (size_t index = 0; index < ArraySize(kSignalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestSignalToString(kSignalTestData[index].signal, kSignalTestData[index].full_name, @@ -170,12 +171,11 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { kAllowFullName | kAllowShortName | kAllowNumber, }; - for (size_t option_index = 0; - option_index < arraysize(kOptions); + for (size_t option_index = 0; option_index < ArraySize(kOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kOptions[option_index]; - for (size_t index = 0; index < arraysize(kSignalTestData); ++index) { + for (size_t index = 0; index < ArraySize(kSignalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); int signal = kSignalTestData[index].signal; { @@ -213,7 +213,7 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { "", }; - for (size_t index = 0; index < arraysize(kNegativeTestData); ++index) { + for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToSignal(kNegativeTestData[index], options, false, 0); } @@ -234,7 +234,7 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { NUL_TEST_DATA("1\0002"), }; - for (size_t index = 0; index < arraysize(kNULTestData); ++index) { + for (size_t index = 0; index < ArraySize(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 fa2a893b..9431d442 100644 --- a/util/process/process_memory_range_test.cc +++ b/util/process/process_memory_range_test.cc @@ -19,9 +19,10 @@ #include "base/logging.h" #include "build/build_config.h" #include "gtest/gtest.h" +#include "test/process_type.h" +#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" -#include "test/process_type.h" namespace crashpad { namespace test { @@ -58,28 +59,28 @@ TEST(ProcessMemoryRange, Basic) { auto string1_addr = FromPointerCast<VMAddress>(kTestObject.string1); auto string2_addr = FromPointerCast<VMAddress>(kTestObject.string2); ASSERT_TRUE(range.ReadCStringSizeLimited( - string1_addr, arraysize(kTestObject.string1), &string)); + string1_addr, ArraySize(kTestObject.string1), &string)); EXPECT_STREQ(string.c_str(), kTestObject.string1); ASSERT_TRUE(range.ReadCStringSizeLimited( - string2_addr, arraysize(kTestObject.string2), &string)); + string2_addr, ArraySize(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, arraysize(kTestObject.string1))); + range2.RestrictRange(string1_addr, ArraySize(kTestObject.string1))); EXPECT_TRUE(range2.ReadCStringSizeLimited( - string1_addr, arraysize(kTestObject.string1), &string)); + string1_addr, ArraySize(kTestObject.string1), &string)); EXPECT_FALSE(range2.ReadCStringSizeLimited( - string2_addr, arraysize(kTestObject.string2), &string)); + string2_addr, ArraySize(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, arraysize(kTestObject.string1), &string)); + string1_addr, ArraySize(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 d855c8d7..ee19429d 100644 --- a/util/stdlib/string_number_conversion_test.cc +++ b/util/stdlib/string_number_conversion_test.cc @@ -18,8 +18,8 @@ #include <limits> -#include "base/macros.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -94,7 +94,7 @@ TEST(StringNumberConversion, StringToInt) { {"18446744073709551616", false, 0}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(kTestData); ++index) { int value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { @@ -114,7 +114,7 @@ TEST(StringNumberConversion, StringToInt) { // is split to avoid MSVC warning: // "decimal digit terminates octal escape sequence". static constexpr char input[] = "6\000" "6"; - std::string input_string(input, arraysize(input) - 1); + std::string input_string(input, ArraySize(input) - 1); int output; EXPECT_FALSE(StringToNumber(input_string, &output)); } @@ -188,7 +188,7 @@ TEST(StringNumberConversion, StringToUnsignedInt) { {"18446744073709551616", false, 0}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(kTestData); ++index) { unsigned int value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { @@ -208,7 +208,7 @@ TEST(StringNumberConversion, StringToUnsignedInt) { // is split to avoid MSVC warning: // "decimal digit terminates octal escape sequence". static constexpr char input[] = "6\000" "6"; - std::string input_string(input, arraysize(input) - 1); + std::string input_string(input, ArraySize(input) - 1); unsigned int output; EXPECT_FALSE(StringToNumber(input_string, &output)); } @@ -245,7 +245,7 @@ TEST(StringNumberConversion, StringToInt64) { {"0x7Fffffffffffffff", true, std::numeric_limits<int64_t>::max()}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(kTestData); ++index) { int64_t value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { @@ -295,7 +295,7 @@ TEST(StringNumberConversion, StringToUnsignedInt64) { {"0xFfffffffffffffff", true, std::numeric_limits<uint64_t>::max()}, }; - for (size_t index = 0; index < arraysize(kTestData); ++index) { + for (size_t index = 0; index < ArraySize(kTestData); ++index) { uint64_t value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { diff --git a/util/stdlib/strlcpy_test.cc b/util/stdlib/strlcpy_test.cc index 5d20e193..172a09ab 100644 --- a/util/stdlib/strlcpy_test.cc +++ b/util/stdlib/strlcpy_test.cc @@ -20,10 +20,10 @@ #include <algorithm> #include "base/format_macros.h" -#include "base/macros.h" #include "base/strings/string16.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -64,7 +64,7 @@ TEST(strlcpy, c16lcpy) { static constexpr base::char16 test_characters[] = {0x4d, 0xe9, 0x100, 0x151, 0x1e18}; - for (size_t index = 0; index < arraysize(test_characters); ++index) { + for (size_t index = 0; index < ArraySize(test_characters); ++index) { base::char16 test_character = test_characters[index]; SCOPED_TRACE(base::StringPrintf( "character index %" PRIuS ", character 0x%x", index, test_character)); @@ -78,13 +78,13 @@ TEST(strlcpy, c16lcpy) { EXPECT_EQ(c16lcpy(destination.data, test_string.c_str(), - arraysize(destination.data)), + ArraySize(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, arraysize(destination.data) - 1); + std::min(length, ArraySize(destination.data) - 1); EXPECT_EQ(destination.data[expected_destination_length], '\0'); EXPECT_EQ(C16Len(destination.data), expected_destination_length); @@ -97,15 +97,15 @@ TEST(strlcpy, c16lcpy) { // of the buffer passed to c16lcpy. EXPECT_TRUE(C16Memcmp(expected_untouched.lead_guard, destination.lead_guard, - arraysize(destination.lead_guard)) == 0); + ArraySize(destination.lead_guard)) == 0); size_t expected_untouched_length = - arraysize(destination.data) - expected_destination_length - 1; + ArraySize(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, - arraysize(destination.trail_guard)) == 0); + ArraySize(destination.trail_guard)) == 0); } } } diff --git a/util/stdlib/thread_safe_vector_test.cc b/util/stdlib/thread_safe_vector_test.cc index 805360f4..183c6366 100644 --- a/util/stdlib/thread_safe_vector_test.cc +++ b/util/stdlib/thread_safe_vector_test.cc @@ -15,6 +15,7 @@ #include "util/stdlib/thread_safe_vector.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" #include "util/thread/thread.h" namespace crashpad { @@ -53,12 +54,12 @@ TEST(ThreadSafeVector, ThreadSafeVector) { EXPECT_TRUE(vector.empty()); ThreadSafeVectorTestThread threads[100]; - for (size_t index = 0; index < arraysize(threads); ++index) { + for (size_t index = 0; index < ArraySize(threads); ++index) { threads[index].SetTestParameters( &thread_safe_vector, static_cast<int>(index * kElementsPerThread)); } - for (size_t index = 0; index < arraysize(threads); ++index) { + for (size_t index = 0; index < ArraySize(threads); ++index) { threads[index].Start(); if (index % 10 == 0) { @@ -75,8 +76,8 @@ TEST(ThreadSafeVector, ThreadSafeVector) { std::vector<int> drained = thread_safe_vector.Drain(); vector.insert(vector.end(), drained.begin(), drained.end()); - bool found[arraysize(threads) * kElementsPerThread] = {}; - EXPECT_EQ(vector.size(), arraysize(found)); + bool found[ArraySize(threads) * kElementsPerThread] = {}; + EXPECT_EQ(vector.size(), ArraySize(found)); for (int element : vector) { EXPECT_FALSE(found[element]) << element; found[element] = true; diff --git a/util/synchronization/semaphore_test.cc b/util/synchronization/semaphore_test.cc index 10f7546d..fedead13 100644 --- a/util/synchronization/semaphore_test.cc +++ b/util/synchronization/semaphore_test.cc @@ -16,8 +16,8 @@ #include <sys/types.h> -#include "base/macros.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" #if defined(OS_POSIX) #include <pthread.h> @@ -126,7 +126,7 @@ TEST(Semaphore, TenThreaded) { Semaphore semaphore(5); ThreadMainInfo info[10]; size_t iterations = 0; - for (size_t index = 0; index < arraysize(info); ++index) { + for (size_t index = 0; index < ArraySize(info); ++index) { info[index].semaphore = &semaphore; info[index].iterations = index; iterations += info[index].iterations; @@ -138,7 +138,7 @@ TEST(Semaphore, TenThreaded) { semaphore.Signal(); } - for (size_t index = 0; index < arraysize(info); ++index) { + for (size_t index = 0; index < ArraySize(info); ++index) { JoinThread(&info[index]); } } diff --git a/util/thread/thread_log_messages_test.cc b/util/thread/thread_log_messages_test.cc index 00b612ce..f186ed20 100644 --- a/util/thread/thread_log_messages_test.cc +++ b/util/thread/thread_log_messages_test.cc @@ -20,6 +20,7 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" +#include "util/misc/arraysize.h" #include "util/thread/thread.h" namespace crashpad { @@ -93,8 +94,8 @@ TEST(ThreadLogMessages, Basic) { const std::vector<std::string>& log_messages = thread_log_messages.log_messages(); - EXPECT_EQ(log_messages.size(), arraysize(kMessages)); - for (size_t index = 0; index < arraysize(kMessages); ++index) { + EXPECT_EQ(log_messages.size(), ArraySize(kMessages)); + for (size_t index = 0; index < ArraySize(kMessages); ++index) { EXPECT_EQ(MessageString(log_messages[index]), kMessages[index]) << "index " << index; } @@ -173,7 +174,7 @@ TEST(ThreadLogMessages, Multithreaded) { LoggingTestThread threads[20]; int start = 0; - for (size_t index = 0; index < arraysize(threads); ++index) { + for (size_t index = 0; index < ArraySize(threads); ++index) { threads[index].Initialize( index, static_cast<int>(start), static_cast<int>(index)); start += static_cast<int>(index); diff --git a/util/thread/thread_test.cc b/util/thread/thread_test.cc index d92544b6..47a711c0 100644 --- a/util/thread/thread_test.cc +++ b/util/thread/thread_test.cc @@ -14,7 +14,6 @@ #include "util/thread/thread.h" -#include "base/macros.h" #include "gtest/gtest.h" #include "util/synchronization/semaphore.h" diff --git a/util/util.gyp b/util/util.gyp index dc82287e..32be8ba9 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -126,7 +126,7 @@ 'mach/task_for_pid.h', 'misc/address_sanitizer.h', 'misc/address_types.h', - 'misc/arraysize_unsafe.h', + 'misc/arraysize.h', 'misc/as_underlying_type.h', 'misc/capture_context.h', 'misc/capture_context_linux.S', diff --git a/util/util_test.gyp b/util/util_test.gyp index b3c8d419..9edd3dcb 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -65,7 +65,7 @@ 'mach/notify_server_test.cc', 'mach/scoped_task_suspend_test.cc', 'mach/symbolic_constants_mach_test.cc', - 'misc/arraysize_unsafe_test.cc', + 'misc/arraysize_test.cc', 'misc/capture_context_test.cc', 'misc/capture_context_test_util.h', 'misc/capture_context_test_util_linux.cc', diff --git a/util/win/command_line_test.cc b/util/win/command_line_test.cc index 025ef8a7..e5ceef87 100644 --- a/util/win/command_line_test.cc +++ b/util/win/command_line_test.cc @@ -19,10 +19,10 @@ #include <sys/types.h> #include "base/logging.h" -#include "base/macros.h" #include "base/scoped_generic.h" #include "gtest/gtest.h" #include "test/errors.h" +#include "util/misc/arraysize.h" #include "util/win/scoped_local_alloc.h" namespace crashpad { @@ -65,7 +65,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"argument 1", L"argument 2", }; - AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); + AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); } { @@ -77,7 +77,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"argument 2", L"\\some\\path with\\spaces", }; - AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); + AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); } { @@ -89,7 +89,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"she said, \"you had me at hello\"", L"\\some\\path with\\spaces", }; - AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); + AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); } { @@ -102,7 +102,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"argument3", L"argument4", }; - AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); + AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); } { @@ -113,7 +113,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"\\some\\directory with\\spaces\\", L"argument2", }; - AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); + AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); } { @@ -124,7 +124,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"", L"argument2", }; - AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); + AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); } { @@ -159,7 +159,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"\"\"", L" \t\n\v\"", }; - AppendCommandLineArgumentTest(arraysize(kArguments), kArguments); + AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); } } diff --git a/util/win/exception_handler_server.cc b/util/win/exception_handler_server.cc index 6642665c..8ca3d259 100644 --- a/util/win/exception_handler_server.cc +++ b/util/win/exception_handler_server.cc @@ -29,6 +29,7 @@ #include "snapshot/crashpad_info_client_options.h" #include "snapshot/win/process_snapshot_win.h" #include "util/file/file_writer.h" +#include "util/misc/arraysize.h" #include "util/misc/tri_state.h" #include "util/misc/uuid.h" #include "util/win/get_function.h" @@ -307,7 +308,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 < arraysize(thread_handles); ++i) { + for (size_t i = 0; i < ArraySize(thread_handles); ++i) { HANDLE pipe; if (first_pipe_instance_.is_valid()) { pipe = first_pipe_instance_.release(); @@ -359,7 +360,7 @@ void ExceptionHandlerServer::Run(Delegate* delegate) { } // Signal to the named pipe instances that they should terminate. - for (size_t i = 0; i < arraysize(thread_handles); ++i) { + for (size_t i = 0; i < ArraySize(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 442e49f4..118bfef7 100644 --- a/util/win/ntstatus_logging.cc +++ b/util/win/ntstatus_logging.cc @@ -17,6 +17,7 @@ #include <string> #include "base/strings/stringprintf.h" +#include "util/misc/arraysize.h" namespace { @@ -29,7 +30,7 @@ std::string FormatNtstatus(DWORD ntstatus) { ntstatus, 0, msgbuf, - arraysize(msgbuf), + static_cast<DWORD>(ArraySize(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 4fb536d9..412f8da0 100644 --- a/util/win/registration_protocol_win.cc +++ b/util/win/registration_protocol_win.cc @@ -18,7 +18,7 @@ #include <windows.h> #include "base/logging.h" -#include "base/macros.h" +#include "util/misc/arraysize.h" #include "util/win/exception_handler_server.h" #include "util/win/scoped_handle.h" @@ -168,7 +168,7 @@ const void* GetSecurityDescriptorForNamedPipeInstance(size_t* size) { ACL_REVISION, // AclRevision. 0, // Sbz1. sizeof(kSecDescBlob.sacl), // AclSize. - arraysize(kSecDescBlob.sacl.ace), // AceCount. + static_cast<WORD>(ArraySize(kSecDescBlob.sacl.ace)), // AceCount. 0, // Sbz2. }, @@ -188,8 +188,9 @@ const void* GetSecurityDescriptorForNamedPipeInstance(size_t* size) { // sid. { SID_REVISION, // Revision. - // SubAuthorityCount. - arraysize(kSecDescBlob.sacl.ace[0].sid.SubAuthority), + // SubAuthorityCount. + static_cast<BYTE>( + ArraySize(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 f9db161b..a62fb143 100644 --- a/util/win/safe_terminate_process_test.cc +++ b/util/win/safe_terminate_process_test.cc @@ -27,6 +27,7 @@ #include "test/errors.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" +#include "util/misc/arraysize.h" #include "util/win/scoped_handle.h" namespace crashpad { @@ -148,7 +149,7 @@ TEST(SafeTerminateProcess, PatchBadly) { }; void* target = reinterpret_cast<void*>(TerminateProcess); - ScopedExecutablePatch executable_patch(target, patch, arraysize(patch)); + ScopedExecutablePatch executable_patch(target, patch, ArraySize(patch)); // Make sure that SafeTerminateProcess() can be called. Since it’s been // patched with a no-op stub, GetLastError() shouldn’t be modified. From e5ff36fb9586737bf2276ce1498ed15b47065091 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Fri, 21 Dec 2018 13:42:51 -0800 Subject: [PATCH 111/401] Use CrashpadInfoReader in ModuleSnapshotWin In preparation for deleting the custom CrashpadInfo reading routines in the PEImageReader and also deleting the PEImageAnnotationsReader, this change moves ModuleSnapshotWin to using the platform-independent CrashpadInfoReader. Bug: crashpad:270 Change-Id: Idad5de173200068243eacb2bb11b2d95b6438e90 Reviewed-on: https://chromium-review.googlesource.com/c/1388017 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/BUILD.gn | 14 ++++- .../crashpad_types/crashpad_info_reader.cc | 7 +-- .../crashpad_info_reader_test.cc | 5 -- snapshot/win/module_snapshot_win.cc | 61 +++++++++++-------- snapshot/win/module_snapshot_win.h | 14 +++-- snapshot/win/pe_image_reader.cc | 37 +++++++++++ snapshot/win/pe_image_reader.h | 17 ++++++ 7 files changed, 113 insertions(+), 42 deletions(-) diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 8d331fc0..89257140 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -142,10 +142,16 @@ static_library("snapshot") { ] } - if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) { + if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia || + crashpad_is_win) { sources += [ "crashpad_types/crashpad_info_reader.cc", "crashpad_types/crashpad_info_reader.h", + ] + } + + if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) { + sources += [ "crashpad_types/image_annotation_reader.cc", "crashpad_types/image_annotation_reader.h", "elf/elf_dynamic_array_reader.cc", @@ -332,9 +338,13 @@ source_set("snapshot_test") { sources += [ "crashpad_info_client_options_test.cc" ] } + if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia || + crashpad_is_win) { + sources += [ "crashpad_types/crashpad_info_reader_test.cc" ] + } + if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) { sources += [ - "crashpad_types/crashpad_info_reader_test.cc", "crashpad_types/image_annotation_reader_test.cc", "elf/elf_image_reader_test.cc", "elf/elf_image_reader_test_note.S", diff --git a/snapshot/crashpad_types/crashpad_info_reader.cc b/snapshot/crashpad_types/crashpad_info_reader.cc index dfc438fc..527d3723 100644 --- a/snapshot/crashpad_types/crashpad_info_reader.cc +++ b/snapshot/crashpad_types/crashpad_info_reader.cc @@ -66,9 +66,8 @@ class CrashpadInfoReader::InfoContainerSpecific : public InfoContainer { return false; } - if (!memory->Read(address, - std::min(VMSize{info.size}, VMSize{sizeof(info)}), - &info)) { + if (!memory->Read( + address, std::min<VMSize>(info.size, sizeof(info)), &info)) { return false; } @@ -116,7 +115,7 @@ class CrashpadInfoReader::InfoContainerSpecific : public InfoContainer { #define NATIVE_TRAITS Traits32 #endif static_assert(!std::is_same<Traits, NATIVE_TRAITS>::value || - sizeof(info) == sizeof(CrashpadInfo), + sizeof(decltype(info)) == sizeof(CrashpadInfo), "CrashpadInfo size mismtach"); #undef NATIVE_TRAITS }; diff --git a/snapshot/crashpad_types/crashpad_info_reader_test.cc b/snapshot/crashpad_types/crashpad_info_reader_test.cc index 87bafc68..ebc6a4d3 100644 --- a/snapshot/crashpad_types/crashpad_info_reader_test.cc +++ b/snapshot/crashpad_types/crashpad_info_reader_test.cc @@ -15,7 +15,6 @@ #include "snapshot/crashpad_types/crashpad_info_reader.h" #include <sys/types.h> -#include <unistd.h> #include <memory> @@ -31,10 +30,6 @@ #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" -#if defined(OS_FUCHSIA) -#include <zircon/process.h> -#endif - namespace crashpad { namespace test { namespace { diff --git a/snapshot/win/module_snapshot_win.cc b/snapshot/win/module_snapshot_win.cc index d76a187e..d9d74c1b 100644 --- a/snapshot/win/module_snapshot_win.cc +++ b/snapshot/win/module_snapshot_win.cc @@ -33,14 +33,16 @@ ModuleSnapshotWin::ModuleSnapshotWin() name_(), pdb_name_(), uuid_(), - pe_image_reader_(), + memory_range_(), + streams_(), + vs_fixed_file_info_(), + initialized_vs_fixed_file_info_(), process_reader_(nullptr), + pe_image_reader_(), + crashpad_info_(), timestamp_(0), age_(0), - initialized_(), - vs_fixed_file_info_(), - initialized_vs_fixed_file_info_() { -} + initialized_() {} ModuleSnapshotWin::~ModuleSnapshotWin() { } @@ -75,6 +77,26 @@ bool ModuleSnapshotWin::Initialize( pdb_name_ = base::UTF16ToUTF8(name_); } + if (!memory_range_.Initialize(process_reader_->Memory(), + process_reader_->Is64Bit())) { + return false; + } + + WinVMAddress crashpad_info_address; + WinVMSize crashpad_info_size; + if (pe_image_reader_->GetCrashpadInfoSection(&crashpad_info_address, + &crashpad_info_size)) { + ProcessMemoryRange info_range; + info_range.Initialize(memory_range_); + info_range.RestrictRange(crashpad_info_address, + crashpad_info_address + crashpad_info_size); + + auto info = std::make_unique<CrashpadInfoReader>(); + if (info->Initialize(&info_range, crashpad_info_address)) { + crashpad_info_ = std::move(info); + } + } + INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -228,8 +250,7 @@ ModuleSnapshotWin::CustomMinidumpStreams() const { template <class Traits> void ModuleSnapshotWin::GetCrashpadOptionsInternal( CrashpadInfoClientOptions* options) { - process_types::CrashpadInfo<Traits> crashpad_info; - if (!pe_image_reader_->GetCrashpadInfo(&crashpad_info)) { + if (!crashpad_info_) { options->crashpad_handler_behavior = TriState::kUnset; options->system_crash_reporter_forwarding = TriState::kUnset; options->gather_indirectly_referenced_memory = TriState::kUnset; @@ -238,19 +259,13 @@ void ModuleSnapshotWin::GetCrashpadOptionsInternal( } options->crashpad_handler_behavior = - CrashpadInfoClientOptions::TriStateFromCrashpadInfo( - crashpad_info.crashpad_handler_behavior); - + crashpad_info_->CrashpadHandlerBehavior(); options->system_crash_reporter_forwarding = - CrashpadInfoClientOptions::TriStateFromCrashpadInfo( - crashpad_info.system_crash_reporter_forwarding); - + crashpad_info_->SystemCrashReporterForwarding(); options->gather_indirectly_referenced_memory = - CrashpadInfoClientOptions::TriStateFromCrashpadInfo( - crashpad_info.gather_indirectly_referenced_memory); - + crashpad_info_->GatherIndirectlyReferencedMemory(); options->indirectly_referenced_memory_cap = - crashpad_info.indirectly_referenced_memory_cap; + crashpad_info_->IndirectlyReferencedMemoryCap(); } const VS_FIXEDFILEINFO* ModuleSnapshotWin::VSFixedFileInfo() const { @@ -270,16 +285,13 @@ const VS_FIXEDFILEINFO* ModuleSnapshotWin::VSFixedFileInfo() const { template <class Traits> void ModuleSnapshotWin::GetCrashpadExtraMemoryRanges( std::set<CheckedRange<uint64_t>>* ranges) const { - process_types::CrashpadInfo<Traits> crashpad_info; - if (!pe_image_reader_->GetCrashpadInfo(&crashpad_info) || - !crashpad_info.extra_address_ranges) { + if (!crashpad_info_ || !crashpad_info_->ExtraMemoryRanges()) return; - } std::vector<SimpleAddressRangeBag::Entry> simple_ranges( SimpleAddressRangeBag::num_entries); if (!process_reader_->Memory()->Read( - crashpad_info.extra_address_ranges, + crashpad_info_->ExtraMemoryRanges(), simple_ranges.size() * sizeof(simple_ranges[0]), &simple_ranges[0])) { LOG(WARNING) << "could not read simple address_ranges from " @@ -298,11 +310,10 @@ void ModuleSnapshotWin::GetCrashpadExtraMemoryRanges( template <class Traits> void ModuleSnapshotWin::GetCrashpadUserMinidumpStreams( std::vector<std::unique_ptr<const UserMinidumpStream>>* streams) const { - process_types::CrashpadInfo<Traits> crashpad_info; - if (!pe_image_reader_->GetCrashpadInfo(&crashpad_info)) + if (!crashpad_info_) return; - for (uint64_t cur = crashpad_info.user_data_minidump_stream_head; cur;) { + for (uint64_t cur = crashpad_info_->UserDataMinidumpStreamHead(); cur;) { internal::UserDataMinidumpStreamListEntry list_entry; if (!process_reader_->Memory()->Read( cur, sizeof(list_entry), &list_entry)) { diff --git a/snapshot/win/module_snapshot_win.h b/snapshot/win/module_snapshot_win.h index 693588db..f18a8809 100644 --- a/snapshot/win/module_snapshot_win.h +++ b/snapshot/win/module_snapshot_win.h @@ -25,6 +25,7 @@ #include "base/macros.h" #include "snapshot/crashpad_info_client_options.h" +#include "snapshot/crashpad_types/crashpad_info_reader.h" #include "snapshot/module_snapshot.h" #include "snapshot/win/process_reader_win.h" #include "util/misc/initialization_state.h" @@ -109,18 +110,19 @@ class ModuleSnapshotWin final : public ModuleSnapshot { std::wstring name_; std::string pdb_name_; UUID uuid_; - std::unique_ptr<PEImageReader> pe_image_reader_; - ProcessReaderWin* process_reader_; // weak - time_t timestamp_; - uint32_t age_; + ProcessMemoryRange memory_range_; // Too const-y: https://crashpad.chromium.org/bug/9. mutable std::vector<std::unique_ptr<const UserMinidumpStream>> streams_; - InitializationStateDcheck initialized_; - // VSFixedFileInfo() is logically const, but updates these members on the // call. See https://crashpad.chromium.org/bug/9. mutable VS_FIXEDFILEINFO vs_fixed_file_info_; mutable InitializationState initialized_vs_fixed_file_info_; + ProcessReaderWin* process_reader_; // weak + std::unique_ptr<PEImageReader> pe_image_reader_; + std::unique_ptr<CrashpadInfoReader> crashpad_info_; + time_t timestamp_; + uint32_t age_; + InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ModuleSnapshotWin); }; diff --git a/snapshot/win/pe_image_reader.cc b/snapshot/win/pe_image_reader.cc index 094cf0fd..b4b1d169 100644 --- a/snapshot/win/pe_image_reader.cc +++ b/snapshot/win/pe_image_reader.cc @@ -72,6 +72,18 @@ bool PEImageReader::Initialize(ProcessReaderWin* process_reader, return true; } +bool PEImageReader::GetCrashpadInfoSection(WinVMAddress* address, + WinVMSize* size) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (module_subrange_reader_.Is64Bit()) { + return GetCrashpadInfoSectionInternal<process_types::internal::Traits64>( + address, size); + } else { + return GetCrashpadInfoSectionInternal<process_types::internal::Traits32>( + address, size); + } +} + template <class Traits> bool PEImageReader::GetCrashpadInfo( process_types::CrashpadInfo<Traits>* crashpad_info) const { @@ -294,6 +306,31 @@ bool PEImageReader::VSFixedFileInfo( return true; } +template <class Traits> +bool PEImageReader::GetCrashpadInfoSectionInternal(WinVMAddress* address, + WinVMSize* size) const { + IMAGE_SECTION_HEADER section; + if (!GetSectionByName<typename NtHeadersForTraits<Traits>::type>("CPADinfo", + §ion)) { + return false; + } + + process_types::CrashpadInfo<Traits> crashpad_info; + if (section.Misc.VirtualSize < + offsetof(process_types::CrashpadInfo<Traits>, size) + + sizeof(crashpad_info.size)) { + LOG(WARNING) << "small crashpad info section size " + << section.Misc.VirtualSize << ", " + << module_subrange_reader_.name(); + return false; + } + + *address = Address() + section.VirtualAddress; + *size = std::min<WinVMSize>(sizeof(crashpad_info), section.Misc.VirtualSize); + + return true; +} + template <class NtHeadersType> bool PEImageReader::ReadNtHeaders(NtHeadersType* nt_headers, WinVMAddress* nt_headers_address) const { diff --git a/snapshot/win/pe_image_reader.h b/snapshot/win/pe_image_reader.h index 56a991b8..ebdbe578 100644 --- a/snapshot/win/pe_image_reader.h +++ b/snapshot/win/pe_image_reader.h @@ -94,6 +94,16 @@ class PEImageReader { //! This is the value passed as \a size to Initialize(). WinVMSize Size() const { return module_subrange_reader_.Size(); } + //! \brief Obtains the module's CrashpadInfo structure address and size. + //! + //! \param[out] address The CrashpadInfo structure address. + //! \param[out] size The CrashpadInfo structure size. + //! + //! \return `true` on success, `false` on failure. If the module does not have + //! a `CPADinfo` section, this will return `false` without logging any + //! messages. Other failures will result in messages being logged. + bool GetCrashpadInfoSection(WinVMAddress* address, WinVMSize* size) const; + //! \brief Obtains the module's CrashpadInfo structure. //! //! \return `true` on success, `false` on failure. If the module does not have @@ -137,6 +147,13 @@ class PEImageReader { bool VSFixedFileInfo(VS_FIXEDFILEINFO* vs_fixed_file_info) const; private: + //! \brief Performs the internal logic for GetCrashpadInfoSection(). + //! + //! \sa GetCrashpadInfoSection + template <class Traits> + bool GetCrashpadInfoSectionInternal(WinVMAddress* address, + WinVMSize* size) const; + //! \brief Reads the `IMAGE_NT_HEADERS` from the beginning of the image. //! //! \param[out] nt_headers The contents of the templated NtHeadersType From 3678bff13fe0ba6f7e129cbb371709eb0b0d3492 Mon Sep 17 00:00:00 2001 From: Eric Astor <epastor@google.com> Date: Thu, 3 Jan 2019 15:10:16 -0500 Subject: [PATCH 112/401] Separates generating & fixing Mach interfaces with MIG. Adds new scripts: mig_gen.py for using MIG to generate a Mach interface, mig_fix.py for fixing the resulting interface. mig.py now wraps both into the same user interface. mig_fix.py also has the option to write its fixed output to new files, rather than overwriting the existing output. This should increase compatibility with certain build configurations. Change-Id: I743ea1bab3f63c5b92f361948b544d498ed01cbc Reviewed-on: https://chromium-review.googlesource.com/c/1389095 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/mach/mig.py | 144 +++---------------------------- util/mach/mig_fix.py | 197 +++++++++++++++++++++++++++++++++++++++++++ util/mach/mig_gen.py | 67 +++++++++++++++ 3 files changed, 274 insertions(+), 134 deletions(-) create mode 100755 util/mach/mig_fix.py create mode 100755 util/mach/mig_gen.py diff --git a/util/mach/mig.py b/util/mach/mig.py index 9833c8c5..c2357338 100755 --- a/util/mach/mig.py +++ b/util/mach/mig.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # coding: utf-8 -# Copyright 2014 The Crashpad Authors. All rights reserved. +# 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. @@ -15,143 +15,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -import argparse -import os -import re -import subprocess import sys -def FixUserImplementation(implementation): - """Rewrites a MIG-generated user implementation (.c) file. - - Rewrites the file at |implementation| by adding “__attribute__((unused))” to - the definition of any structure typedefed as “__Reply” by searching for the - pattern unique to those structure definitions. These structures are in fact - 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. - """ - - file = open(implementation, 'r+') - contents = file.read() - - pattern = re.compile('^(\t} __Reply);$', re.MULTILINE) - contents = pattern.sub(r'\1 __attribute__((unused));', contents) - - file.seek(0) - file.truncate() - file.write(contents) - file.close() - -def FixServerImplementation(implementation): - """Rewrites a MIG-generated server implementation (.c) file. - - Rewrites the file at |implementation| by replacing “mig_internal” with - “mig_external” on functions that begin with “__MIG_check__”. This makes these - functions available to other callers outside this file from a linkage - perspective. It then returns, as a list of lines, declarations that can be - added to a header file, so that other files that include that header file will - have access to these declarations from a compilation perspective. - """ - - file = open(implementation, 'r+') - contents = file.read() - - # Find interesting declarations. - declaration_pattern = \ - re.compile('^mig_internal (kern_return_t __MIG_check__.*)$', - re.MULTILINE) - declarations = declaration_pattern.findall(contents) - - # Remove “__attribute__((__unused__))” from the declarations, and call them - # “mig_external” or “extern” depending on whether “mig_external” is defined. - attribute_pattern = re.compile(r'__attribute__\(\(__unused__\)\) ') - declarations = ['#ifdef mig_external\nmig_external\n#else\nextern\n#endif\n' + - attribute_pattern.sub('', x) + - ';\n' for x in declarations] - - # Rewrite the declarations in this file as “mig_external”. - contents = declaration_pattern.sub(r'mig_external \1', contents); - - # Crashpad never implements the mach_msg_server() MIG callouts. To avoid - # needing to provide stub implementations, set KERN_FAILURE as the RetCode - # and abort(). - routine_callout_pattern = re.compile( - r'OutP->RetCode = (([a-zA-Z0-9_]+)\(.+\));') - routine_callouts = routine_callout_pattern.findall(contents) - for routine in routine_callouts: - contents = contents.replace(routine[0], 'KERN_FAILURE; abort()') - - # Include the header for abort(). - contents = '#include <stdlib.h>\n' + contents - - file.seek(0) - file.truncate() - file.write(contents) - file.close() - return declarations - -def FixHeader(header, declarations=[]): - """Rewrites a MIG-generated header (.h) file. - - Rewrites the file at |header| by placing it inside an “extern "C"” block, so - that it declares things properly when included by a C++ compilation unit. - |declarations| can be a list of additional declarations to place inside the - “extern "C"” block after the original contents of |header|. - """ - - file = open(header, 'r+') - contents = file.read() - declarations_text = ''.join(declarations) - contents = '''\ -#ifdef __cplusplus -extern "C" { -#endif - -%s -%s -#ifdef __cplusplus -} -#endif -''' % (contents, declarations_text) - file.seek(0) - file.truncate() - file.write(contents) - file.close() +import mig_fix +import mig_gen def main(args): - parser = argparse.ArgumentParser() - parser.add_argument('--developer-dir', help='Path to Xcode') - parser.add_argument('--sdk', help='Path to SDK') - parser.add_argument('--include', - default=[], - action='append', - help='Additional include directory') - parser.add_argument('defs') - parser.add_argument('user_c') - parser.add_argument('server_c') - parser.add_argument('user_h') - parser.add_argument('server_h') - parsed = parser.parse_args(args) + parsed = mig_gen.parse_args(args) - command = ['mig', - '-user', parsed.user_c, - '-server', parsed.server_c, - '-header', parsed.user_h, - '-sheader', parsed.server_h, - ] - if parsed.developer_dir is not None: - os.environ['DEVELOPER_DIR'] = parsed.developer_dir - if parsed.sdk is not None: - command.extend(['-isysroot', parsed.sdk]) - for include in parsed.include: - command.extend(['-I' + include]) - command.append(parsed.defs) - subprocess.check_call(command) - FixUserImplementation(parsed.user_c) - server_declarations = FixServerImplementation(parsed.server_c) - FixHeader(parsed.user_h) - FixHeader(parsed.server_h, server_declarations) + interface = mig_gen.MigInterface(parsed.user_c, parsed.server_c, + parsed.user_h, parsed.server_h) + mig_gen.generate_interface(parsed.defs, interface, parsed.include, + parsed.developer_dir, parsed.sdk) + mig_fix.fix_interface(interface) if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + sys.exit(main(sys.argv[1:])) diff --git a/util/mach/mig_fix.py b/util/mach/mig_fix.py new file mode 100755 index 00000000..8cd5e4f6 --- /dev/null +++ b/util/mach/mig_fix.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python +# coding: utf-8 + +# 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. + +import argparse +import os +import re +import sys + +from mig_gen import MigInterface + +def _fix_user_implementation(implementation, fixed_implementation, header, + fixed_header): + """Rewrites a MIG-generated user implementation (.c) file. + + Rewrites the file at |implementation| by adding + “__attribute__((unused))” to the definition of any structure typedefed + as “__Reply” by searching for the pattern unique to those structure + definitions. These structures are in fact 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. + + If |fixed_implementation| is None, overwrites the original; otherwise, puts + the result in the file at |fixed_implementation|. + """ + + file = open(implementation, 'r+' if fixed_implementation is None else 'r') + contents = file.read() + + pattern = re.compile('^(\t} __Reply);$', re.MULTILINE) + contents = pattern.sub(r'\1 __attribute__((unused));', contents) + + if fixed_header is not None: + contents = contents.replace( + '#include "%s"' % os.path.basename(header), + '#include "%s"' % os.path.basename(fixed_header)) + + if fixed_implementation is None: + file.seek(0) + file.truncate() + else: + file.close() + file = open(fixed_implementation, 'w') + file.write(contents) + file.close() + +def _fix_server_implementation(implementation, fixed_implementation, header, + fixed_header): + """Rewrites a MIG-generated server implementation (.c) file. + + Rewrites the file at |implementation| by replacing “mig_internal” with + “mig_external” on functions that begin with “__MIG_check__”. This makes + these functions available to other callers outside this file from a linkage + perspective. It then returns, as a list of lines, declarations that can be + 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. + + If |fixed_implementation| is None or not provided, overwrites the original; + otherwise, puts the result in the file at |fixed_implementation|. + """ + + file = open(implementation, 'r+' if fixed_implementation is None else 'r') + contents = file.read() + + # Find interesting declarations. + declaration_pattern = \ + re.compile('^mig_internal (kern_return_t __MIG_check__.*)$', + re.MULTILINE) + declarations = declaration_pattern.findall(contents) + + # Remove “__attribute__((__unused__))” from the declarations, and call them + # “mig_external” or “extern” depending on whether “mig_external” is defined. + attribute_pattern = re.compile(r'__attribute__\(\(__unused__\)\) ') + declarations = ['''\ +#ifdef mig_external +mig_external +#else +extern +#endif +''' + attribute_pattern.sub('', x) + ';\n' for x in declarations] + + # Rewrite the declarations in this file as “mig_external”. + contents = declaration_pattern.sub(r'mig_external \1', contents); + + # Crashpad never implements the mach_msg_server() MIG callouts. To avoid + # needing to provide stub implementations, set KERN_FAILURE as the RetCode + # and abort(). + routine_callout_pattern = re.compile( + r'OutP->RetCode = (([a-zA-Z0-9_]+)\(.+\));') + routine_callouts = routine_callout_pattern.findall(contents) + for routine in routine_callouts: + contents = contents.replace(routine[0], 'KERN_FAILURE; abort()') + + # Include the header for abort(). + contents = '#include <stdlib.h>\n' + contents + + if fixed_header is not None: + contents = contents.replace( + '#include "%s"' % os.path.basename(header), + '#include "%s"' % os.path.basename(fixed_header)) + + if fixed_implementation is None: + file.seek(0) + file.truncate() + else: + file.close() + file = open(fixed_implementation, 'w') + file.write(contents) + file.close() + return declarations + +def _fix_header(header, fixed_header, declarations=[]): + """Rewrites a MIG-generated header (.h) file. + + Rewrites the file at |header| by placing it inside an “extern "C"” block, so + that it declares things properly when included by a C++ compilation unit. + |declarations| can be a list of additional declarations to place inside the + “extern "C"” block after the original contents of |header|. + + If |fixed_header| is None or not provided, overwrites the original; + otherwise, puts the result in the file at |fixed_header|. + """ + + file = open(header, 'r+' if fixed_header is None else 'r') + contents = file.read() + declarations_text = ''.join(declarations) + contents = '''\ +#ifdef __cplusplus +extern "C" { +#endif + +%s +%s +#ifdef __cplusplus +} +#endif +''' % (contents, declarations_text) + + if fixed_header is None: + file.seek(0) + file.truncate() + else: + file.close() + file = open(fixed_header, 'w') + file.write(contents) + file.close() + +def fix_interface(interface, fixed_interface=None): + if fixed_interface is None: + fixed_interface = MigInterface(None, None, None, None) + + _fix_user_implementation(interface.user_c, fixed_interface.user_c, + interface.user_h, fixed_interface.user_h) + server_declarations = _fix_server_implementation(interface.server_c, + fixed_interface.server_c, + interface.server_h, + fixed_interface.server_h) + _fix_header(interface.user_h, fixed_interface.user_h) + _fix_header(interface.server_h, fixed_interface.server_h, + server_declarations) + +def main(args): + parser = argparse.ArgumentParser() + parser.add_argument('user_c') + parser.add_argument('--fixed_user_c', default=None) + parser.add_argument('server_c') + parser.add_argument('--fixed_server_c', default=None) + parser.add_argument('user_h') + parser.add_argument('--fixed_user_h', default=None) + parser.add_argument('server_h') + parser.add_argument('--fixed_server_h', default=None) + parsed = parser.parse_args(args) + + interface = MigInterface(parsed.user_c, parsed.server_c, + parsed.user_h, parsed.server_h) + fixed_interface = MigInterface(parsed.fixed_user_c, parsed.fixed_server_c, + parsed.fixed_user_h, parsed.fixed_server_h) + fix_interface(interface, fixed_interface) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/util/mach/mig_gen.py b/util/mach/mig_gen.py new file mode 100755 index 00000000..d71029a4 --- /dev/null +++ b/util/mach/mig_gen.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# coding: utf-8 + +# 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. + +import argparse +import collections +import os +import subprocess +import sys + +MigInterface = collections.namedtuple('MigInterface', ['user_c', 'server_c', + 'user_h', 'server_h']) + +def generate_interface(defs, interface, includes=[], + developer_dir=None, sdk=None): + command = ['mig', + '-user', interface.user_c, + '-server', interface.server_c, + '-header', interface.user_h, + '-sheader', interface.server_h, + ] + if developer_dir is not None: + os.environ['DEVELOPER_DIR'] = developer_dir + if sdk is not None: + command.extend(['-isysroot', sdk]) + for include in includes: + command.extend(['-I' + include]) + command.append(defs) + subprocess.check_call(command) + +def parse_args(args): + parser = argparse.ArgumentParser() + parser.add_argument('--developer-dir', help='Path to Xcode') + parser.add_argument('--sdk', help='Path to SDK') + parser.add_argument('--include', + default=[], + action='append', + help='Additional include directory') + parser.add_argument('defs') + parser.add_argument('user_c') + parser.add_argument('server_c') + parser.add_argument('user_h') + parser.add_argument('server_h') + return parser.parse_args(args) + +def main(args): + parsed = parse_args(args) + interface = MigInterface(parsed.user_c, parsed.server_c, + parsed.user_h, parsed.server_h) + generate_interface(parsed.defs, interface, parsed.include, + parsed.developer_dir, parsed.sdk) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) From bc1b4e833e823729b2d8564d061f473456a218f1 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 3 Jan 2019 12:26:07 -0800 Subject: [PATCH 113/401] Update comment to reflect current state Bug: crashpad:270 Change-Id: I51869f3f613057f617d8f73ca6643bfe2ab75573 Reviewed-on: https://chromium-review.googlesource.com/c/1394154 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- snapshot/mac/mach_o_image_annotations_reader.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/snapshot/mac/mach_o_image_annotations_reader.cc b/snapshot/mac/mach_o_image_annotations_reader.cc index e730b511..eefd7f44 100644 --- a/snapshot/mac/mach_o_image_annotations_reader.cc +++ b/snapshot/mac/mach_o_image_annotations_reader.cc @@ -178,9 +178,9 @@ void MachOImageAnnotationsReader::ReadCrashpadSimpleAnnotations( } } -// TODO(rsesek): When there is a platform-agnostic remote memory reader -// interface available, use it so that the implementation is not duplicated -// in the PEImageAnnotationsReader. +// TODO(https://crbug.com/crashpad/270): Replace implementations of +// ReadCrashpadAnnotationsList and ReadCrashpadSimpleAnnotations with the +// platform-agnostic implementations in ImageAnnotationReader. void MachOImageAnnotationsReader::ReadCrashpadAnnotationsList( std::vector<AnnotationSnapshot>* annotations) const { process_types::CrashpadInfo crashpad_info; From cc166d71f48ff45fb9d171920ee9ca92b4ec0957 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 4 Jan 2019 16:57:57 -0500 Subject: [PATCH 114/401] Use base::size where appropriate, and ArraySize elsewhere MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow-up to c8a016b99d97, following the post-landing discussion at https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1393921/5#message-2058541d8c4505d20a990ab7734cd758e437a5f7 base::size, and std::size that will eventually replace it when C++17 is assured, does not allow the size of non-static data members to be taken in constant expression context. The remaining uses of ArraySize are in: minidump/minidump_exception_writer.cc (×1) minidump/minidump_system_info_writer.cc (×2, also uses base::size) snapshot/cpu_context.cc (×4, also uses base::size) util/misc/arraysize_test.cc (×10, of course) The first of these occurs when initializing a constexpr variable. All others are in expressions used with static_assert. Includes: Update mini_chromium to 737433ebade4d446643c6c07daae02a67e8deccao f701716d9546 Add Windows ARM64 build target to mini_chromium 87a95a3d6ac2 Remove the arraysize macro 1f7255ead1f7 Placate MSVC in areas of base::size usage 737433ebade4 Add cast Bug: chromium:837308 Change-Id: I6a5162654461b1bdd9b7b6864d0d71a734bcde19 Reviewed-on: https://chromium-review.googlesource.com/c/1396108 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- client/crash_report_database_mac.mm | 4 +- client/simulate_crash_mac.cc | 6 +- client/simulate_crash_mac_test.cc | 8 +-- handler/mac/file_limit_annotation.cc | 4 +- handler/win/crashy_test_program.cc | 6 +- handler/win/hanging_program.cc | 4 +- 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 | 3 +- minidump/minidump_thread_id_map_test.cc | 7 +- minidump/minidump_thread_writer_test.cc | 12 ++-- minidump/minidump_writable.cc | 4 +- minidump/test/minidump_context_test_util.cc | 72 ++++++++++--------- snapshot/capture_memory.cc | 8 +-- snapshot/cpu_context.cc | 5 +- snapshot/cpu_context_test.cc | 22 +++--- .../memory_map_region_snapshot_fuchsia.cc | 4 +- .../fuchsia/process_reader_fuchsia_test.cc | 4 +- .../fuchsia/process_snapshot_fuchsia_test.cc | 8 +-- .../linux/exception_snapshot_linux_test.cc | 12 ++-- snapshot/linux/process_reader_linux_test.cc | 4 +- snapshot/mac/mach_o_image_reader.cc | 7 +- .../mac/mach_o_image_segment_reader_test.cc | 8 +-- snapshot/mac/process_reader_mac_test.cc | 8 +-- snapshot/mac/process_types.cc | 4 +- snapshot/mac/process_types/custom.cc | 6 +- snapshot/mac/process_types_test.cc | 8 +-- .../process_snapshot_minidump_test.cc | 24 +++---- snapshot/minidump/thread_snapshot_minidump.cc | 18 ++--- snapshot/posix/timezone.cc | 5 +- snapshot/posix/timezone_test.cc | 4 +- .../sanitization_information_test.cc | 6 +- snapshot/test/test_cpu_context.cc | 32 ++++----- snapshot/win/cpu_context_win_test.cc | 8 +-- .../crashpad_snapshot_test_image_reader.cc | 8 +-- snapshot/win/pe_image_annotations_reader.cc | 5 +- snapshot/win/pe_image_reader.cc | 4 +- snapshot/win/process_reader_win_test.cc | 6 +- snapshot/win/process_snapshot_win.cc | 8 +-- test/hex_string.h | 4 +- test/hex_string_test.cc | 4 +- 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/direct_ptrace_connection.cc | 4 +- util/linux/proc_stat_reader.cc | 4 +- 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 | 4 +- .../composite_mach_message_server_test.cc | 14 ++-- util/mach/exc_client_variants_test.cc | 10 +-- util/mach/exc_server_variants.cc | 8 +-- util/mach/exc_server_variants_test.cc | 40 +++++------ util/mach/exception_behaviors_test.cc | 4 +- util/mach/exception_types_test.cc | 8 +-- util/mach/mach_message_server_test.cc | 4 +- util/mach/notify_server.cc | 4 +- util/mach/symbolic_constants_mach.cc | 27 +++---- util/mach/symbolic_constants_mach_test.cc | 49 ++++++------- util/misc/arraysize.h | 4 ++ util/misc/capture_context_test_util_win.cc | 8 +-- util/misc/clock_test.cc | 4 +- util/misc/paths_win.cc | 10 +-- util/misc/random_string_test.cc | 6 +- util/misc/uuid_test.cc | 10 +-- util/net/http_transport_socket.cc | 4 +- util/net/http_transport_win.cc | 4 +- 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 | 10 +-- util/posix/scoped_mmap_test.cc | 12 ++-- util/posix/signals.cc | 13 ++-- util/posix/signals_test.cc | 4 +- util/posix/symbolic_constants_posix.cc | 10 +-- util/posix/symbolic_constants_posix_test.cc | 14 ++-- util/process/process_memory_range_test.cc | 14 ++-- util/stdlib/string_number_conversion_test.cc | 14 ++-- util/stdlib/strlcpy_test.cc | 14 ++-- util/stdlib/thread_safe_vector_test.cc | 10 +-- util/synchronization/semaphore_test.cc | 6 +- util/thread/thread_log_messages_test.cc | 8 +-- util/win/command_line_test.cc | 16 ++--- util/win/exception_handler_server.cc | 6 +- util/win/ntstatus_logging.cc | 4 +- util/win/registration_protocol_win.cc | 9 +-- util/win/safe_terminate_process_test.cc | 4 +- 100 files changed, 500 insertions(+), 481 deletions(-) diff --git a/DEPS b/DEPS index 635e1416..10c37bc3 100644 --- a/DEPS +++ b/DEPS @@ -30,7 +30,7 @@ deps = { '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '4a6189577978b86fbd6935aec0d16a127803467c', + '737433ebade4d446643c6c07daae02a67e8decca', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 0980fe3f..414dd5a4 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -29,13 +29,13 @@ #include "base/mac/scoped_nsautorelease_pool.h" #include "base/posix/eintr_wrapper.h" #include "base/scoped_generic.h" +#include "base/stl_util.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "base/strings/sys_string_conversions.h" #include "client/settings.h" #include "util/file/file_io.h" #include "util/mac/xattr.h" -#include "util/misc/arraysize.h" #include "util/misc/initialization_state_dcheck.h" #include "util/misc/metrics.h" @@ -280,7 +280,7 @@ bool CrashReportDatabaseMac::Initialize(bool may_create) { } // Create the three processing directories for the database. - for (size_t i = 0; i < ArraySize(kReportDirectories); ++i) { + for (size_t i = 0; i < base::size(kReportDirectories); ++i) { if (!CreateOrEnsureDirectoryExists(base_dir_.Append(kReportDirectories[i]))) return false; } diff --git a/client/simulate_crash_mac.cc b/client/simulate_crash_mac.cc index 1f7eca9e..43d05b81 100644 --- a/client/simulate_crash_mac.cc +++ b/client/simulate_crash_mac.cc @@ -20,13 +20,13 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/mac/scoped_mach_port.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "util/mach/exc_client_variants.h" #include "util/mach/exception_behaviors.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -191,7 +191,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 = ArraySize(codes); + mach_msg_type_number_t code_count = base::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 @@ -213,7 +213,7 @@ void SimulateCrash(const NativeCPUContext& cpu_context) { bool success = false; for (size_t target_type_index = 0; - !success && target_type_index < ArraySize(kTargetTypes); + !success && target_type_index < base::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 910971ae..c2f4c204 100644 --- a/client/simulate_crash_mac_test.cc +++ b/client/simulate_crash_mac_test.cc @@ -19,6 +19,7 @@ #include <sys/types.h> #include "base/macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -31,7 +32,6 @@ #include "util/mach/mach_message.h" #include "util/mach/mach_message_server.h" #include "util/mach/symbolic_constants_mach.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -343,13 +343,13 @@ TEST(SimulateCrash, SimulateCrash) { #endif }; - for (size_t target_index = 0; target_index < ArraySize(kTargets); + for (size_t target_index = 0; target_index < base::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 < ArraySize(kBehaviors); + for (size_t behavior_index = 0; behavior_index < base::size(kBehaviors); ++behavior_index) { exception_behavior_t behavior = kBehaviors[behavior_index]; SCOPED_TRACE(base::StringPrintf( @@ -363,7 +363,7 @@ TEST(SimulateCrash, SimulateCrash) { target, behavior, THREAD_STATE_NONE); test_simulate_crash_mac.Run(); } else { - for (size_t flavor_index = 0; flavor_index < ArraySize(kFlavors); + for (size_t flavor_index = 0; flavor_index < base::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 5646bdea..a01e87d9 100644 --- a/handler/mac/file_limit_annotation.cc +++ b/handler/mac/file_limit_annotation.cc @@ -24,10 +24,10 @@ #include <string> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" #include "client/simple_string_dictionary.h" -#include "util/misc/arraysize.h" #include "util/posix/scoped_dir.h" namespace crashpad { @@ -108,7 +108,7 @@ void RecordFileLimitAnnotation() { int mib[] = {CTL_KERN, KERN_MAXFILES}; size = sizeof(value); std::string max_files = FormatFromSysctl( - sysctl(mib, ArraySize(mib), &value, &size, nullptr, 0), &value, &size); + sysctl(mib, base::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 d6b4dead..990929bf 100644 --- a/handler/win/crashy_test_program.cc +++ b/handler/win/crashy_test_program.cc @@ -26,10 +26,10 @@ #include "base/files/file_path.h" #include "base/logging.h" +#include "base/stl_util.h" #include "build/build_config.h" #include "client/crashpad_client.h" #include "client/crashpad_info.h" -#include "util/misc/arraysize.h" #include "util/win/critical_section_with_debug_info.h" #include "util/win/get_function.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, ArraySize(kPageTypes) * kPageSize, MEM_RESERVE, PAGE_READWRITE); + nullptr, base::size(kPageTypes) * kPageSize, MEM_RESERVE, PAGE_READWRITE); PCHECK(reserve) << "VirtualAlloc MEM_RESERVE"; uintptr_t reserve_as_int = reinterpret_cast<uintptr_t>(reserve); - for (size_t i = 0; i < ArraySize(kPageTypes); ++i) { + for (size_t i = 0; i < base::size(kPageTypes); ++i) { void* result = VirtualAlloc(reinterpret_cast<void*>(reserve_as_int + (kPageSize * i)), kPageSize, diff --git a/handler/win/hanging_program.cc b/handler/win/hanging_program.cc index 49d5cea4..f4e5b983 100644 --- a/handler/win/hanging_program.cc +++ b/handler/win/hanging_program.cc @@ -17,11 +17,11 @@ #include "base/debug/alias.h" #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "client/crashpad_client.h" #include "client/crashpad_info.h" -#include "util/misc/arraysize.h" namespace { @@ -124,7 +124,7 @@ int wmain(int argc, wchar_t* argv[]) { // This is not expected to return. DWORD count = WaitForMultipleObjects( - static_cast<DWORD>(ArraySize(threads)), threads, true, INFINITE); + static_cast<DWORD>(base::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 f86ff467..dc05cc64 100644 --- a/minidump/minidump_annotation_writer_test.cc +++ b/minidump/minidump_annotation_writer_test.cc @@ -16,13 +16,13 @@ #include <memory> +#include "base/stl_util.h" #include "gtest/gtest.h" #include "minidump/minidump_extensions.h" #include "minidump/test/minidump_byte_array_writer_test_util.h" #include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -107,7 +107,7 @@ TEST(MinidumpAnnotationWriter, ThreeItems) { MinidumpAnnotationListWriter list_writer; - for (size_t i = 0; i < ArraySize(kNames); ++i) { + for (size_t i = 0; i < base::size(kNames); ++i) { auto annotation = std::make_unique<MinidumpAnnotationWriter>(); 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 94fad5c6..e4cd526e 100644 --- a/minidump/minidump_byte_array_writer_test.cc +++ b/minidump/minidump_byte_array_writer_test.cc @@ -17,11 +17,11 @@ #include <memory> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -35,7 +35,7 @@ TEST(MinidumpByteArrayWriter, Write) { {}, }; - for (size_t i = 0; i < ArraySize(kTests); ++i) { + for (size_t i = 0; i < base::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 < ArraySize(kTests); ++i) { + for (size_t i = 0; i < base::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 b3a4e809..75adbee2 100644 --- a/minidump/minidump_exception_writer_test.cc +++ b/minidump/minidump_exception_writer_test.cc @@ -17,6 +17,7 @@ #include <string> #include <utility> +#include "base/stl_util.h" #include "gtest/gtest.h" #include "minidump/minidump_context.h" #include "minidump/minidump_context_writer.h" @@ -29,7 +30,6 @@ #include "snapshot/test/test_exception_snapshot.h" #include "test/gtest_death.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -81,7 +81,7 @@ void ExpectExceptionStream(const MINIDUMP_EXCEPTION_STREAM* expected, expected->ExceptionRecord.NumberParameters); EXPECT_EQ(observed->ExceptionRecord.__unusedAlignment, 0u); for (size_t index = 0; - index < ArraySize(observed->ExceptionRecord.ExceptionInformation); + index < base::size(observed->ExceptionRecord.ExceptionInformation); ++index) { EXPECT_EQ(observed->ExceptionRecord.ExceptionInformation[index], expected->ExceptionRecord.ExceptionInformation[index]); diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index ef4813ed..84832292 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -20,6 +20,7 @@ #include <string> #include <utility> +#include "base/stl_util.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "minidump/minidump_stream_writer.h" @@ -36,7 +37,6 @@ #include "snapshot/test/test_thread_snapshot.h" #include "test/gtest_death.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -135,7 +135,7 @@ TEST(MinidumpFileWriter, AddUserExtensionStream) { minidump_file.SetTimestamp(kTimestamp); static constexpr uint8_t kStreamData[] = "Hello World!"; - constexpr size_t kStreamSize = ArraySize(kStreamData); + constexpr size_t kStreamSize = base::size(kStreamData); constexpr MinidumpStreamType kStreamType = static_cast<MinidumpStreamType>(0x4d); diff --git a/minidump/minidump_memory_writer_test.cc b/minidump/minidump_memory_writer_test.cc index fa71caf0..90287cba 100644 --- a/minidump/minidump_memory_writer_test.cc +++ b/minidump/minidump_memory_writer_test.cc @@ -17,6 +17,7 @@ #include <utility> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "minidump/minidump_extensions.h" @@ -26,7 +27,6 @@ #include "minidump/test/minidump_writable_test_util.h" #include "snapshot/test/test_memory_snapshot.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -341,7 +341,7 @@ TEST(MinidumpMemoryWriter, ExtraMemory) { TEST(MinidumpMemoryWriter, AddFromSnapshot) { MINIDUMP_MEMORY_DESCRIPTOR expect_memory_descriptors[3] = {}; - uint8_t values[ArraySize(expect_memory_descriptors)] = {}; + uint8_t values[base::size(expect_memory_descriptors)] = {}; expect_memory_descriptors[0].StartOfMemoryRange = 0; expect_memory_descriptors[0].Memory.DataSize = 0x1000; @@ -357,7 +357,7 @@ TEST(MinidumpMemoryWriter, AddFromSnapshot) { std::vector<std::unique_ptr<TestMemorySnapshot>> memory_snapshots_owner; std::vector<const MemorySnapshot*> memory_snapshots; - for (size_t index = 0; index < ArraySize(expect_memory_descriptors); + for (size_t index = 0; index < base::size(expect_memory_descriptors); ++index) { memory_snapshots_owner.push_back(std::make_unique<TestMemorySnapshot>()); TestMemorySnapshot* memory_snapshot = memory_snapshots_owner.back().get(); @@ -396,7 +396,7 @@ TEST(MinidumpMemoryWriter, AddFromSnapshot) { TEST(MinidumpMemoryWriter, CoalesceExplicitMultiple) { MINIDUMP_MEMORY_DESCRIPTOR expect_memory_descriptors[4] = {}; - uint8_t values[ArraySize(expect_memory_descriptors)] = {}; + uint8_t values[base::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 2d70d00a..a1340760 100644 --- a/minidump/minidump_misc_info_writer.cc +++ b/minidump/minidump_misc_info_writer.cc @@ -18,6 +18,7 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" @@ -26,7 +27,6 @@ #include "snapshot/process_snapshot.h" #include "snapshot/system_snapshot.h" #include "util/file/file_writer.h" -#include "util/misc/arraysize.h" #include "util/numeric/in_range_cast.h" #include "util/numeric/safe_assignment.h" @@ -302,7 +302,7 @@ void MinidumpMiscInfoWriter::SetTimeZone(uint32_t time_zone_id, internal::MinidumpWriterUtil::AssignUTF8ToUTF16( misc_info_.TimeZone.StandardName, - ArraySize(misc_info_.TimeZone.StandardName), + base::size(misc_info_.TimeZone.StandardName), standard_name); misc_info_.TimeZone.StandardDate = standard_date; @@ -310,7 +310,7 @@ void MinidumpMiscInfoWriter::SetTimeZone(uint32_t time_zone_id, internal::MinidumpWriterUtil::AssignUTF8ToUTF16( misc_info_.TimeZone.DaylightName, - ArraySize(misc_info_.TimeZone.DaylightName), + base::size(misc_info_.TimeZone.DaylightName), daylight_name); misc_info_.TimeZone.DaylightDate = daylight_date; @@ -327,10 +327,10 @@ void MinidumpMiscInfoWriter::SetBuildString( misc_info_.Flags1 |= MINIDUMP_MISC4_BUILDSTRING; internal::MinidumpWriterUtil::AssignUTF8ToUTF16( - misc_info_.BuildString, ArraySize(misc_info_.BuildString), build_string); + misc_info_.BuildString, base::size(misc_info_.BuildString), build_string); internal::MinidumpWriterUtil::AssignUTF8ToUTF16( misc_info_.DbgBldStr, - ArraySize(misc_info_.DbgBldStr), + base::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 e134ccd2..bd927338 100644 --- a/minidump/minidump_misc_info_writer_test.cc +++ b/minidump/minidump_misc_info_writer_test.cc @@ -21,6 +21,7 @@ #include "base/compiler_specific.h" #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -31,7 +32,6 @@ #include "snapshot/test/test_process_snapshot.h" #include "snapshot/test/test_system_snapshot.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" #include "util/stdlib/strlcpy.h" namespace crashpad { @@ -127,7 +127,7 @@ void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_3>( SCOPED_TRACE("Standard"); ExpectNULPaddedString16Equal(expected->TimeZone.StandardName, observed->TimeZone.StandardName, - ArraySize(expected->TimeZone.StandardName)); + base::size(expected->TimeZone.StandardName)); ExpectSystemTimeEqual(&expected->TimeZone.StandardDate, &observed->TimeZone.StandardDate); EXPECT_EQ(observed->TimeZone.StandardBias, expected->TimeZone.StandardBias); @@ -136,7 +136,7 @@ void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_3>( SCOPED_TRACE("Daylight"); ExpectNULPaddedString16Equal(expected->TimeZone.DaylightName, observed->TimeZone.DaylightName, - ArraySize(expected->TimeZone.DaylightName)); + base::size(expected->TimeZone.DaylightName)); ExpectSystemTimeEqual(&expected->TimeZone.DaylightDate, &observed->TimeZone.DaylightDate); EXPECT_EQ(observed->TimeZone.DaylightBias, expected->TimeZone.DaylightBias); @@ -154,13 +154,13 @@ void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_4>( SCOPED_TRACE("BuildString"); ExpectNULPaddedString16Equal(expected->BuildString, observed->BuildString, - ArraySize(expected->BuildString)); + base::size(expected->BuildString)); } { SCOPED_TRACE("DbgBldStr"); ExpectNULPaddedString16Equal(expected->DbgBldStr, observed->DbgBldStr, - ArraySize(expected->DbgBldStr)); + base::size(expected->DbgBldStr)); } } @@ -176,7 +176,7 @@ void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_5>( EXPECT_EQ(observed->XStateData.EnabledFeatures, expected->XStateData.EnabledFeatures); for (size_t feature_index = 0; - feature_index < ArraySize(observed->XStateData.Features); + feature_index < base::size(observed->XStateData.Features); ++feature_index) { SCOPED_TRACE(base::StringPrintf("feature_index %" PRIuS, feature_index)); EXPECT_EQ(observed->XStateData.Features[feature_index].Offset, @@ -396,7 +396,7 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); c16lcpy(expected.TimeZone.StandardName, standard_name_utf16.c_str(), - ArraySize(expected.TimeZone.StandardName)); + base::size(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kStandardDate, sizeof(expected.TimeZone.StandardDate)); @@ -404,7 +404,7 @@ TEST(MinidumpMiscInfoWriter, TimeZone) { base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); c16lcpy(expected.TimeZone.DaylightName, daylight_name_utf16.c_str(), - ArraySize(expected.TimeZone.DaylightName)); + base::size(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kDaylightDate, sizeof(expected.TimeZone.DaylightDate)); @@ -424,9 +424,9 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { constexpr int32_t kBias = 300; MINIDUMP_MISC_INFO_N tmp; ALLOW_UNUSED_LOCAL(tmp); - std::string standard_name(ArraySize(tmp.TimeZone.StandardName) + 1, 's'); + std::string standard_name(base::size(tmp.TimeZone.StandardName) + 1, 's'); constexpr int32_t kStandardBias = 0; - std::string daylight_name(ArraySize(tmp.TimeZone.DaylightName), 'd'); + std::string daylight_name(base::size(tmp.TimeZone.DaylightName), 'd'); constexpr int32_t kDaylightBias = -60; // Test using kSystemTimeZero, because not all platforms will be able to @@ -457,7 +457,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { base::string16 standard_name_utf16 = base::UTF8ToUTF16(standard_name); c16lcpy(expected.TimeZone.StandardName, standard_name_utf16.c_str(), - ArraySize(expected.TimeZone.StandardName)); + base::size(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); @@ -465,7 +465,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) { base::string16 daylight_name_utf16 = base::UTF8ToUTF16(daylight_name); c16lcpy(expected.TimeZone.DaylightName, daylight_name_utf16.c_str(), - ArraySize(expected.TimeZone.DaylightName)); + base::size(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kSystemTimeZero, sizeof(expected.TimeZone.DaylightDate)); @@ -496,12 +496,12 @@ TEST(MinidumpMiscInfoWriter, BuildStrings) { base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); c16lcpy(expected.BuildString, build_string_utf16.c_str(), - ArraySize(expected.BuildString)); + base::size(expected.BuildString)); base::string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); c16lcpy(expected.DbgBldStr, debug_build_string_utf16.c_str(), - ArraySize(expected.DbgBldStr)); + base::size(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -515,8 +515,8 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { MINIDUMP_MISC_INFO_N tmp; ALLOW_UNUSED_LOCAL(tmp); - std::string build_string(ArraySize(tmp.BuildString) + 1, 'B'); - std::string debug_build_string(ArraySize(tmp.DbgBldStr), 'D'); + std::string build_string(base::size(tmp.BuildString) + 1, 'B'); + std::string debug_build_string(base::size(tmp.DbgBldStr), 'D'); misc_info_writer->SetBuildString(build_string, debug_build_string); @@ -533,12 +533,12 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) { base::string16 build_string_utf16 = base::UTF8ToUTF16(build_string); c16lcpy(expected.BuildString, build_string_utf16.c_str(), - ArraySize(expected.BuildString)); + base::size(expected.BuildString)); base::string16 debug_build_string_utf16 = base::UTF8ToUTF16(debug_build_string); c16lcpy(expected.DbgBldStr, debug_build_string_utf16.c_str(), - ArraySize(expected.DbgBldStr)); + base::size(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -678,7 +678,7 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::string16 standard_name_utf16 = base::UTF8ToUTF16(kStandardName); c16lcpy(expected.TimeZone.StandardName, standard_name_utf16.c_str(), - ArraySize(expected.TimeZone.StandardName)); + base::size(expected.TimeZone.StandardName)); memcpy(&expected.TimeZone.StandardDate, &kSystemTimeZero, sizeof(expected.TimeZone.StandardDate)); @@ -686,7 +686,7 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::string16 daylight_name_utf16 = base::UTF8ToUTF16(kDaylightName); c16lcpy(expected.TimeZone.DaylightName, daylight_name_utf16.c_str(), - ArraySize(expected.TimeZone.DaylightName)); + base::size(expected.TimeZone.DaylightName)); memcpy(&expected.TimeZone.DaylightDate, &kSystemTimeZero, sizeof(expected.TimeZone.DaylightDate)); @@ -694,12 +694,12 @@ TEST(MinidumpMiscInfoWriter, Everything) { base::string16 build_string_utf16 = base::UTF8ToUTF16(kBuildString); c16lcpy(expected.BuildString, build_string_utf16.c_str(), - ArraySize(expected.BuildString)); + base::size(expected.BuildString)); base::string16 debug_build_string_utf16 = base::UTF8ToUTF16(kDebugBuildString); c16lcpy(expected.DbgBldStr, debug_build_string_utf16.c_str(), - ArraySize(expected.DbgBldStr)); + base::size(expected.DbgBldStr)); ExpectMiscInfoEqual(&expected, observed); } @@ -743,18 +743,18 @@ TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) { expect_misc_info.TimeZone.Bias = 300; c16lcpy(expect_misc_info.TimeZone.StandardName, standard_time_name_utf16.c_str(), - ArraySize(expect_misc_info.TimeZone.StandardName)); + base::size(expect_misc_info.TimeZone.StandardName)); expect_misc_info.TimeZone.StandardBias = 0; c16lcpy(expect_misc_info.TimeZone.DaylightName, daylight_time_name_utf16.c_str(), - ArraySize(expect_misc_info.TimeZone.DaylightName)); + base::size(expect_misc_info.TimeZone.DaylightName)); expect_misc_info.TimeZone.DaylightBias = -60; c16lcpy(expect_misc_info.BuildString, build_string_utf16.c_str(), - ArraySize(expect_misc_info.BuildString)); + base::size(expect_misc_info.BuildString)); c16lcpy(expect_misc_info.DbgBldStr, debug_build_string_utf16.c_str(), - ArraySize(expect_misc_info.DbgBldStr)); + base::size(expect_misc_info.DbgBldStr)); const timeval kStartTime = { static_cast<time_t>(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 83401eca..ba4ab05b 100644 --- a/minidump/minidump_module_crashpad_info_writer_test.cc +++ b/minidump/minidump_module_crashpad_info_writer_test.cc @@ -19,6 +19,7 @@ #include <utility> +#include "base/stl_util.h" #include "gtest/gtest.h" #include "minidump/minidump_annotation_writer.h" #include "minidump/minidump_simple_string_dictionary_writer.h" @@ -28,7 +29,6 @@ #include "minidump/test/minidump_writable_test_util.h" #include "snapshot/test/test_module_snapshot.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -155,9 +155,9 @@ TEST(MinidumpModuleCrashpadInfoWriter, FullModule) { sizeof(MinidumpSimpleStringDictionaryEntry) + sizeof(MinidumpAnnotationList) + 2 + // padding sizeof(MinidumpAnnotation) + sizeof(MinidumpUTF8String) + - ArraySize(kEntry) + 2 + // padding - sizeof(MinidumpUTF8String) + ArraySize(kKey) + - sizeof(MinidumpUTF8String) + ArraySize(kValue) + + base::size(kEntry) + 2 + // padding + sizeof(MinidumpUTF8String) + base::size(kKey) + + sizeof(MinidumpUTF8String) + base::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 bef6a8c6..8b5fc062 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -20,6 +20,7 @@ #include <utility> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" @@ -30,7 +31,6 @@ #include "snapshot/test/test_module_snapshot.h" #include "test/gtest_death.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/misc/uuid.h" @@ -651,10 +651,10 @@ void InitializeTestModuleSnapshotFromMinidumpModule( TEST(MinidumpModuleWriter, InitializeFromSnapshot) { MINIDUMP_MODULE expect_modules[3] = {}; - const char* module_paths[ArraySize(expect_modules)] = {}; - const char* module_pdbs[ArraySize(expect_modules)] = {}; - UUID uuids[ArraySize(expect_modules)] = {}; - uint32_t ages[ArraySize(expect_modules)] = {}; + 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)] = {}; expect_modules[0].BaseOfImage = 0x100101000; expect_modules[0].SizeOfImage = 0xf000; @@ -706,7 +706,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { std::vector<std::unique_ptr<TestModuleSnapshot>> module_snapshots_owner; std::vector<const ModuleSnapshot*> module_snapshots; - for (size_t index = 0; index < ArraySize(expect_modules); ++index) { + for (size_t index = 0; index < base::size(expect_modules); ++index) { module_snapshots_owner.push_back(std::make_unique<TestModuleSnapshot>()); 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 bd376a9f..38074324 100644 --- a/minidump/minidump_rva_list_writer_test.cc +++ b/minidump/minidump_rva_list_writer_test.cc @@ -17,12 +17,12 @@ #include <utility> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "minidump/test/minidump_rva_list_test_util.h" #include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -87,10 +87,10 @@ TEST(MinidumpRVAListWriter, ThreeChildren) { ASSERT_TRUE(list_writer.WriteEverything(&string_file)); const MinidumpRVAList* list = - MinidumpRVAListAtStart(string_file.string(), ArraySize(kValues)); + MinidumpRVAListAtStart(string_file.string(), base::size(kValues)); ASSERT_TRUE(list); - for (size_t index = 0; index < ArraySize(kValues); ++index) { + for (size_t index = 0; index < base::size(kValues); ++index) { SCOPED_TRACE(base::StringPrintf("index %" PRIuS, index)); const uint32_t* child = MinidumpWritableAtRVA<uint32_t>( diff --git a/minidump/minidump_string_writer_test.cc b/minidump/minidump_string_writer_test.cc index aa735039..ddb8c486 100644 --- a/minidump/minidump_string_writer_test.cc +++ b/minidump/minidump_string_writer_test.cc @@ -18,6 +18,7 @@ #include "base/compiler_specific.h" #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" @@ -25,7 +26,6 @@ #include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -67,15 +67,16 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) { {4, "\360\220\204\202", 2, {0xd800, 0xdd02}}, // 𐄂 (non-BMP) }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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[ArraySize(kTestData[index].output_string) - 1], - 0); + ASSERT_EQ( + kTestData[index] + .output_string[base::size(kTestData[index].output_string) - 1], + 0); string_file.Reset(); crashpad::internal::MinidumpUTF16StringWriter string_writer; @@ -119,7 +120,7 @@ TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) { "\303\0\251", // NUL in middle of valid sequence }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::size(kTestData); ++index) { SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ", input %s", index, kTestData[index])); string_file.Reset(); @@ -182,7 +183,7 @@ TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) { {4, "\360\220\204\202"}, // 𐄂 (non-BMP) }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 df0e348b..9bc013dc 100644 --- a/minidump/minidump_system_info_writer.cc +++ b/minidump/minidump_system_info_writer.cc @@ -17,6 +17,7 @@ #include <string.h> #include "base/logging.h" +#include "base/stl_util.h" #include "minidump/minidump_string_writer.h" #include "snapshot/system_snapshot.h" #include "util/file/file_writer.h" @@ -230,7 +231,7 @@ void MinidumpSystemInfoWriter::SetCPUX86VendorString( sizeof(registers) == sizeof(system_info_.Cpu.X86CpuInfo.VendorId), "VendorId sizes must be equal"); - for (size_t index = 0; index < ArraySize(registers); ++index) { + for (size_t index = 0; index < base::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 d64d8106..548729e6 100644 --- a/minidump/minidump_thread_id_map_test.cc +++ b/minidump/minidump_thread_id_map_test.cc @@ -19,9 +19,9 @@ #include <vector> #include "base/macros.h" +#include "base/stl_util.h" #include "gtest/gtest.h" #include "snapshot/test/test_thread_snapshot.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -39,7 +39,8 @@ class MinidumpThreadIDMapTest : public testing::Test { // testing::Test: void SetUp() override { - for (size_t index = 0; index < ArraySize(test_thread_snapshots_); ++index) { + for (size_t index = 0; index < base::size(test_thread_snapshots_); + ++index) { thread_snapshots_.push_back(&test_thread_snapshots_[index]); } } @@ -60,7 +61,7 @@ class MinidumpThreadIDMapTest : public testing::Test { } void SetThreadID(size_t index, uint64_t thread_id) { - ASSERT_LT(index, ArraySize(test_thread_snapshots_)); + ASSERT_LT(index, base::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 63269ced..956d1005 100644 --- a/minidump/minidump_thread_writer_test.cc +++ b/minidump/minidump_thread_writer_test.cc @@ -19,6 +19,7 @@ #include "base/compiler_specific.h" #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "minidump/minidump_context_writer.h" @@ -33,7 +34,6 @@ #include "snapshot/test/test_thread_snapshot.h" #include "test/gtest_death.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -523,10 +523,10 @@ template <typename Traits> void RunInitializeFromSnapshotTest(bool thread_id_collision) { using MinidumpContextType = typename Traits::MinidumpContextType; MINIDUMP_THREAD expect_threads[3] = {}; - uint64_t thread_ids[ArraySize(expect_threads)] = {}; - uint8_t memory_values[ArraySize(expect_threads)] = {}; - uint32_t context_seeds[ArraySize(expect_threads)] = {}; - MINIDUMP_MEMORY_DESCRIPTOR tebs[ArraySize(expect_threads)] = {}; + 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)] = {}; constexpr size_t kTebSize = 1024; @@ -582,7 +582,7 @@ void RunInitializeFromSnapshotTest(bool thread_id_collision) { std::vector<std::unique_ptr<TestThreadSnapshot>> thread_snapshots_owner; std::vector<const ThreadSnapshot*> thread_snapshots; - for (size_t index = 0; index < ArraySize(expect_threads); ++index) { + for (size_t index = 0; index < base::size(expect_threads); ++index) { thread_snapshots_owner.push_back(std::make_unique<TestThreadSnapshot>()); TestThreadSnapshot* thread_snapshot = thread_snapshots_owner.back().get(); diff --git a/minidump/minidump_writable.cc b/minidump/minidump_writable.cc index c8075c61..fa3e2f16 100644 --- a/minidump/minidump_writable.cc +++ b/minidump/minidump_writable.cc @@ -17,8 +17,8 @@ #include <stdint.h> #include "base/logging.h" +#include "base/stl_util.h" #include "util/file/file_writer.h" -#include "util/misc/arraysize.h" #include "util/numeric/safe_assignment.h" namespace { @@ -245,7 +245,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_, ArraySize(kZeroes)); + DCHECK_LE(leading_pad_bytes_, base::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 ae80d003..c94fa20d 100644 --- a/minidump/test/minidump_context_test_util.cc +++ b/minidump/test/minidump_context_test_util.cc @@ -18,12 +18,12 @@ #include <sys/types.h> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "snapshot/cpu_context.h" #include "snapshot/test/test_cpu_context.h" #include "test/hex_string.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -128,7 +128,8 @@ void InitializeMinidumpContextAMD64(MinidumpContextAMD64* context, context->ds = static_cast<uint16_t>(value++); context->es = static_cast<uint16_t>(value++); context->ss = static_cast<uint16_t>(value++); - for (size_t index = 0; index < ArraySize(context->vector_register); ++index) { + for (size_t index = 0; index < base::size(context->vector_register); + ++index) { context->vector_register[index].lo = value++; context->vector_register[index].hi = value++; } @@ -151,7 +152,7 @@ void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed) { uint32_t value = seed; - for (size_t index = 0; index < ArraySize(context->regs); ++index) { + for (size_t index = 0; index < base::size(context->regs); ++index) { context->regs[index] = value++; } context->fp = value++; @@ -162,7 +163,7 @@ void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed) { context->pc = value++; context->cpsr = value++; - for (size_t index = 0; index < ArraySize(context->vfp); ++index) { + for (size_t index = 0; index < base::size(context->vfp); ++index) { context->vfp[index] = value++; } context->fpscr = value++; @@ -180,7 +181,7 @@ void InitializeMinidumpContextARM64(MinidumpContextARM64* context, uint32_t value = seed; - for (size_t index = 0; index < ArraySize(context->regs); ++index) { + for (size_t index = 0; index < base::size(context->regs); ++index) { context->regs[index] = value++; } context->fp = value++; @@ -189,7 +190,7 @@ void InitializeMinidumpContextARM64(MinidumpContextARM64* context, context->pc = value++; context->cpsr = value++; - for (size_t index = 0; index < ArraySize(context->fpsimd); ++index) { + for (size_t index = 0; index < base::size(context->fpsimd); ++index) { context->fpsimd[index].lo = value++; context->fpsimd[index].hi = value++; } @@ -209,7 +210,7 @@ void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, uint32_t value = seed; - for (size_t index = 0; index < ArraySize(context->regs); ++index) { + for (size_t index = 0; index < base::size(context->regs); ++index) { context->regs[index] = value++; } @@ -220,7 +221,7 @@ void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, context->status = value++; context->cause = value++; - for (size_t index = 0; index < ArraySize(context->fpregs.fregs); ++index) { + for (size_t index = 0; index < base::size(context->fpregs.fregs); ++index) { context->fpregs.fregs[index]._fp_fregs = static_cast<float>(value++); } @@ -247,7 +248,7 @@ void InitializeMinidumpContextMIPS64(MinidumpContextMIPS64* context, uint64_t value = seed; - for (size_t index = 0; index < ArraySize(context->regs); ++index) { + for (size_t index = 0; index < base::size(context->regs); ++index) { context->regs[index] = value++; } @@ -258,7 +259,7 @@ void InitializeMinidumpContextMIPS64(MinidumpContextMIPS64* context, context->status = value++; context->cause = value++; - for (size_t index = 0; index < ArraySize(context->fpregs.dregs); ++index) { + for (size_t index = 0; index < base::size(context->fpregs.dregs); ++index) { context->fpregs.dregs[index] = static_cast<double>(value++); } context->fpcsr = value++; @@ -293,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 < ArraySize(expected->st_mm); + for (size_t st_mm_index = 0; st_mm_index < base::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, - ArraySize(observed->st_mm[st_mm_index].st)), + base::size(observed->st_mm[st_mm_index].st)), BytesToHexString(expected->st_mm[st_mm_index].st, - ArraySize(expected->st_mm[st_mm_index].st))); + base::size(expected->st_mm[st_mm_index].st))); EXPECT_EQ( BytesToHexString(observed->st_mm[st_mm_index].st_reserved, - ArraySize(observed->st_mm[st_mm_index].st_reserved)), + base::size(observed->st_mm[st_mm_index].st_reserved)), BytesToHexString(expected->st_mm[st_mm_index].st_reserved, - ArraySize(expected->st_mm[st_mm_index].st_reserved))); + base::size(expected->st_mm[st_mm_index].st_reserved))); } - for (size_t xmm_index = 0; xmm_index < ArraySize(expected->xmm); + for (size_t xmm_index = 0; xmm_index < base::size(expected->xmm); ++xmm_index) { EXPECT_EQ(BytesToHexString(observed->xmm[xmm_index], - ArraySize(observed->xmm[xmm_index])), + base::size(observed->xmm[xmm_index])), BytesToHexString(expected->xmm[xmm_index], - ArraySize(expected->xmm[xmm_index]))) + base::size(expected->xmm[xmm_index]))) << "xmm_index " << xmm_index; } EXPECT_EQ( - BytesToHexString(observed->reserved_4, ArraySize(observed->reserved_4)), - BytesToHexString(expected->reserved_4, ArraySize(expected->reserved_4))); + BytesToHexString(observed->reserved_4, base::size(observed->reserved_4)), + BytesToHexString(expected->reserved_4, base::size(expected->reserved_4))); EXPECT_EQ( - BytesToHexString(observed->available, ArraySize(observed->available)), - BytesToHexString(expected->available, ArraySize(expected->available))); + BytesToHexString(observed->available, base::size(observed->available)), + BytesToHexString(expected->available, base::size(expected->available))); } } // namespace @@ -344,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 < ArraySize(expected.fsave.st); ++index) { + for (size_t index = 0; index < base::size(expected.fsave.st); ++index) { EXPECT_EQ(BytesToHexString(observed->fsave.st[index], - ArraySize(observed->fsave.st[index])), + base::size(observed->fsave.st[index])), BytesToHexString(expected.fsave.st[index], - ArraySize(expected.fsave.st[index]))) + base::size(expected.fsave.st[index]))) << "index " << index; } if (snapshot) { @@ -447,7 +448,8 @@ void ExpectMinidumpContextAMD64( ExpectMinidumpContextFxsave(&expected.fxsave, &observed->fxsave); - for (size_t index = 0; index < ArraySize(expected.vector_register); ++index) { + for (size_t index = 0; index < base::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; @@ -487,7 +489,7 @@ void ExpectMinidumpContextARM(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < ArraySize(expected.regs); ++index) { + for (size_t index = 0; index < base::size(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } EXPECT_EQ(observed->fp, expected.fp); @@ -498,10 +500,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 < ArraySize(expected.vfp); ++index) { + for (size_t index = 0; index < base::size(expected.vfp); ++index) { EXPECT_EQ(observed->vfp[index], expected.vfp[index]); } - for (size_t index = 0; index < ArraySize(expected.extra); ++index) { + for (size_t index = 0; index < base::size(expected.extra); ++index) { EXPECT_EQ(observed->extra[index], snapshot ? 0 : expected.extra[index]); } } @@ -514,14 +516,14 @@ void ExpectMinidumpContextARM64(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < ArraySize(expected.regs); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(expected.fpsimd); ++index) { + for (size_t index = 0; index < base::size(expected.fpsimd); ++index) { EXPECT_EQ(observed->fpsimd[index].lo, expected.fpsimd[index].lo); EXPECT_EQ(observed->fpsimd[index].hi, expected.fpsimd[index].hi); } @@ -535,7 +537,7 @@ void ExpectMinidumpContextMIPS(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < ArraySize(expected.regs); ++index) { + for (size_t index = 0; index < base::size(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } @@ -546,7 +548,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 < ArraySize(expected.fpregs.fregs); ++index) { + for (size_t index = 0; index < base::size(expected.fpregs.fregs); ++index) { EXPECT_EQ(observed->fpregs.fregs[index]._fp_fregs, expected.fpregs.fregs[index]._fp_fregs); } @@ -568,7 +570,7 @@ void ExpectMinidumpContextMIPS64(uint32_t expect_seed, EXPECT_EQ(observed->context_flags, expected.context_flags); - for (size_t index = 0; index < ArraySize(expected.regs); ++index) { + for (size_t index = 0; index < base::size(expected.regs); ++index) { EXPECT_EQ(observed->regs[index], expected.regs[index]); } @@ -579,7 +581,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 < ArraySize(expected.fpregs.dregs); ++index) { + for (size_t index = 0; index < base::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 3ffbcd2b..a51626cc 100644 --- a/snapshot/capture_memory.cc +++ b/snapshot/capture_memory.cc @@ -19,8 +19,8 @@ #include <limits> #include <memory> +#include "base/stl_util.h" #include "snapshot/memory_snapshot.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace internal { @@ -98,17 +98,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 < ArraySize(context.arm64->regs); ++i) { + for (size_t i = 0; i < base::size(context.arm64->regs); ++i) { MaybeCaptureMemoryAround(delegate, context.arm64->regs[i]); } } else { MaybeCaptureMemoryAround(delegate, context.arm->pc); - for (size_t i = 0; i < ArraySize(context.arm->regs); ++i) { + for (size_t i = 0; i < base::size(context.arm->regs); ++i) { MaybeCaptureMemoryAround(delegate, context.arm->regs[i]); } } #elif defined(ARCH_CPU_MIPS_FAMILY) - for (size_t i = 0; i < ArraySize(context.mipsel->regs); ++i) { + for (size_t i = 0; i < base::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 0ed16914..6fb8d7e7 100644 --- a/snapshot/cpu_context.cc +++ b/snapshot/cpu_context.cc @@ -18,6 +18,7 @@ #include <string.h> #include "base/logging.h" +#include "base/stl_util.h" #include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" @@ -57,7 +58,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 < ArraySize(fsave->st); ++index) { + for (size_t index = 0; index < base::size(fsave->st); ++index) { memcpy(fsave->st[index], fxsave.st_mm[index].st, sizeof(fsave->st[index])); } } @@ -79,7 +80,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 < ArraySize(fsave.st); ++index) { + for (size_t index = 0; index < base::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 794d9b9f..109510d3 100644 --- a/snapshot/cpu_context_test.cc +++ b/snapshot/cpu_context_test.cc @@ -18,9 +18,9 @@ #include <string.h> #include <sys/types.h> +#include "base/stl_util.h" #include "gtest/gtest.h" #include "test/hex_string.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -124,7 +124,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 < ArraySize(fxsave.st_mm); ++index) { + for (size_t index = 0; index < base::size(fxsave.st_mm); ++index) { memset(&fxsave.st_mm[index].st_reserved, 0x5a, sizeof(fxsave.st_mm[index].st_reserved)); @@ -148,10 +148,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 < ArraySize(fsave.st); ++index) { - EXPECT_EQ(BytesToHexString(fsave.st[index], ArraySize(fsave.st[index])), + for (size_t index = 0; index < base::size(fsave.st); ++index) { + EXPECT_EQ(BytesToHexString(fsave.st[index], base::size(fsave.st[index])), BytesToHexString(fxsave.st_mm[index].st, - ArraySize(fxsave.st_mm[index].st))) + base::size(fxsave.st_mm[index].st))) << "index " << index; } } @@ -204,14 +204,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 < ArraySize(fxsave.st_mm); ++index) { + for (size_t index = 0; index < base::size(fxsave.st_mm); ++index) { EXPECT_EQ(BytesToHexString(fxsave.st_mm[index].st, - ArraySize(fxsave.st_mm[index].st)), - BytesToHexString(fsave.st[index], ArraySize(fsave.st[index]))) + base::size(fxsave.st_mm[index].st)), + BytesToHexString(fsave.st[index], base::size(fsave.st[index]))) << "index " << index; EXPECT_EQ(BytesToHexString(fxsave.st_mm[index].st_reserved, - ArraySize(fxsave.st_mm[index].st_reserved)), - std::string(ArraySize(fxsave.st_mm[index].st_reserved) * 2, '0')) + base::size(fxsave.st_mm[index].st_reserved)), + std::string(base::size(fxsave.st_mm[index].st_reserved) * 2, '0')) << "index " << index; } size_t unused_len = sizeof(fxsave) - offsetof(decltype(fxsave), xmm); @@ -318,7 +318,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 < ArraySize(st_mm); ++index) { + for (size_t index = 0; index < base::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 45d39d2a..1133c4d4 100644 --- a/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc @@ -15,7 +15,7 @@ #include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h" #include "base/logging.h" -#include "util/misc/arraysize.h" +#include "base/stl_util.h" namespace crashpad { namespace internal { @@ -50,7 +50,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, ArraySize(mapping)); + DCHECK_LT(index, base::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 5832a221..83385a85 100644 --- a/snapshot/fuchsia/process_reader_fuchsia_test.cc +++ b/snapshot/fuchsia/process_reader_fuchsia_test.cc @@ -20,11 +20,11 @@ #include <zircon/syscalls/port.h> #include <zircon/types.h> +#include "base/stl_util.h" #include "gtest/gtest.h" #include "test/multiprocess_exec.h" #include "test/test_paths.h" #include "util/fuchsia/scoped_task_suspend.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -35,7 +35,7 @@ TEST(ProcessReaderFuchsia, SelfBasic) { ASSERT_TRUE(process_reader.Initialize(*zx::process::self())); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[ArraySize(kTestMemory)]; + char buffer[base::size(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast<zx_vaddr_t>(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 ebb612be..a96d37c0 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc @@ -19,12 +19,12 @@ #include "base/fuchsia/fuchsia_logging.h" #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "snapshot/fuchsia/process_snapshot_fuchsia.h" #include "test/multiprocess_exec.h" #include "util/fuchsia/scoped_task_suspend.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -104,8 +104,8 @@ class AddressSpaceTest : public MultiprocessExec { private: void MultiprocessParent() override { - uintptr_t test_addresses[ArraySize(kTestMappingPermAndSizes)]; - for (size_t i = 0; i < ArraySize(test_addresses); ++i) { + uintptr_t test_addresses[base::size(kTestMappingPermAndSizes)]; + for (size_t i = 0; i < base::size(test_addresses); ++i) { ASSERT_TRUE(ReadFileExactly( ReadPipeHandle(), &test_addresses[i], sizeof(test_addresses[i]))); } @@ -115,7 +115,7 @@ class AddressSpaceTest : public MultiprocessExec { ProcessSnapshotFuchsia process_snapshot; ASSERT_TRUE(process_snapshot.Initialize(*ChildProcess())); - for (size_t i = 0; i < ArraySize(test_addresses); ++i) { + for (size_t i = 0; i < base::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 e632bc1c..e4ff1ab7 100644 --- a/snapshot/linux/exception_snapshot_linux_test.cc +++ b/snapshot/linux/exception_snapshot_linux_test.cc @@ -23,6 +23,7 @@ #include "base/bit_cast.h" #include "base/macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "snapshot/cpu_architecture.h" @@ -32,7 +33,6 @@ #include "test/errors.h" #include "test/linux/fake_ptrace_connection.h" #include "util/linux/address_types.h" -#include "util/misc/arraysize.h" #include "util/misc/clock.h" #include "util/misc/from_pointer_cast.h" #include "util/posix/signals.h" @@ -171,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 < ArraySize(test_context->vfp.context.vfp.fpregs); + for (size_t reg = 0; reg < base::size(test_context->vfp.context.vfp.fpregs); ++reg) { test_context->vfp.context.vfp.fpregs[reg] = reg; } @@ -219,7 +219,7 @@ struct TestCoprocessorContext { void InitializeContext(NativeCPUContext* context) { memset(context, 'x', sizeof(*context)); - for (size_t index = 0; index < ArraySize(context->uc_mcontext.regs); + for (size_t index = 0; index < base::size(context->uc_mcontext.regs); ++index) { context->uc_mcontext.regs[index] = index; } @@ -238,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 < ArraySize(test_context->fpsimd.vregs); ++reg) { + for (size_t reg = 0; reg < base::size(test_context->fpsimd.vregs); ++reg) { test_context->fpsimd.vregs[reg] = reg; } @@ -271,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 < ArraySize(context->uc_mcontext.gregs); ++reg) { + for (size_t reg = 0; reg < base::size(context->uc_mcontext.gregs); ++reg) { context->uc_mcontext.gregs[reg] = reg; } memset(&context->uc_mcontext.fpregs, 44, sizeof(context->uc_mcontext.fpregs)); @@ -286,7 +286,7 @@ void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) { #define CPU_ARCH_NAME mips64 #endif - for (size_t reg = 0; reg < ArraySize(expected.uc_mcontext.gregs); ++reg) { + for (size_t reg = 0; reg < base::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 61b84f39..e2e5566c 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -33,6 +33,7 @@ #include "base/format_macros.h" #include "base/memory/free_deleter.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -47,7 +48,6 @@ #include "util/file/filesystem.h" #include "util/linux/direct_ptrace_connection.h" #include "util/misc/address_sanitizer.h" -#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/synchronization/semaphore.h" @@ -80,7 +80,7 @@ TEST(ProcessReaderLinux, SelfBasic) { EXPECT_EQ(process_reader.ParentProcessID(), getppid()); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[ArraySize(kTestMemory)]; + char buffer[base::size(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast<LinuxVMAddress>(kTestMemory), sizeof(kTestMemory), diff --git a/snapshot/mac/mach_o_image_reader.cc b/snapshot/mac/mach_o_image_reader.cc index 650b0c77..bd258caf 100644 --- a/snapshot/mac/mach_o_image_reader.cc +++ b/snapshot/mac/mach_o_image_reader.cc @@ -22,13 +22,13 @@ #include <utility> #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" #include "snapshot/mac/mach_o_image_segment_reader.h" #include "snapshot/mac/mach_o_image_symbol_table_reader.h" #include "snapshot/mac/process_reader_mac.h" #include "util/mac/checked_mach_address_range.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace { @@ -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<uint32_t> singleton_indices(ArraySize(kLoadCommandReaders), + std::vector<uint32_t> singleton_indices(base::size(kLoadCommandReaders), kInvalidSegmentIndex); size_t offset = mach_header.Size(); @@ -236,7 +236,8 @@ bool MachOImageReader::Initialize(ProcessReaderMac* process_reader, return false; } - for (size_t reader_index = 0; reader_index < ArraySize(kLoadCommandReaders); + for (size_t reader_index = 0; + reader_index < base::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 cfbddc1e..4731a5fc 100644 --- a/snapshot/mac/mach_o_image_segment_reader_test.cc +++ b/snapshot/mac/mach_o_image_segment_reader_test.cc @@ -16,9 +16,9 @@ #include <mach-o/loader.h> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -63,7 +63,7 @@ TEST(MachOImageSegmentReader, SegmentNameString) { SEG_IMPORT, }; - for (size_t index = 0; index < ArraySize(kSegmentTestData); ++index) { + for (size_t index = 0; index < base::size(kSegmentTestData); ++index) { EXPECT_EQ( MachOImageSegmentReader::SegmentNameString(kSegmentTestData[index]), kSegmentTestData[index]) @@ -106,7 +106,7 @@ TEST(MachOImageSegmentReader, SectionNameString) { SECT_ICON_TIFF, }; - for (size_t index = 0; index < ArraySize(kSectionTestData); ++index) { + for (size_t index = 0; index < base::size(kSectionTestData); ++index) { EXPECT_EQ( MachOImageSegmentReader::SectionNameString(kSectionTestData[index]), kSectionTestData[index]) @@ -169,7 +169,7 @@ TEST(MachOImageSegmentReader, SegmentAndSectionNameString) { {SEG_IMPORT, "", "__IMPORT,"}, }; - for (size_t index = 0; index < ArraySize(kSegmentAndSectionTestData); + for (size_t index = 0; index < base::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 e3f4df17..9325b2c4 100644 --- a/snapshot/mac/process_reader_mac_test.cc +++ b/snapshot/mac/process_reader_mac_test.cc @@ -29,6 +29,7 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" #include "base/posix/eintr_wrapper.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -41,7 +42,6 @@ #include "util/file/file_io.h" #include "util/mac/mac_util.h" #include "util/mach/mach_extensions.h" -#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/synchronization/semaphore.h" @@ -65,7 +65,7 @@ TEST(ProcessReaderMac, SelfBasic) { EXPECT_EQ(process_reader.ParentProcessID(), getppid()); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[ArraySize(kTestMemory)]; + char buffer[base::size(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( FromPointerCast<mach_vm_address_t>(kTestMemory), sizeof(kTestMemory), @@ -613,11 +613,11 @@ class ScopedOpenCLNoOpKernel { const size_t source_lengths[] = { strlen(sources[0]), }; - static_assert(ArraySize(sources) == ArraySize(source_lengths), + static_assert(base::size(sources) == base::size(source_lengths), "arrays must be parallel"); program_ = clCreateProgramWithSource( - context_, ArraySize(sources), sources, source_lengths, &rv); + context_, base::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 9ae8f7c2..0a1b7f95 100644 --- a/snapshot/mac/process_types.cc +++ b/snapshot/mac/process_types.cc @@ -20,8 +20,8 @@ #include <memory> +#include "base/stl_util.h" #include "snapshot/mac/process_types/internal.h" -#include "util/misc/arraysize.h" #include "util/process/process_memory_mac.h" namespace crashpad { @@ -74,7 +74,7 @@ using UInt64Array4 = uint64_t[4]; template <> inline void Assign<UInt64Array4, UInt32Array4>(UInt64Array4* destination, const UInt32Array4& source) { - for (size_t index = 0; index < ArraySize(source); ++index) { + for (size_t index = 0; index < base::size(source); ++index) { (*destination)[index] = source[index]; } } diff --git a/snapshot/mac/process_types/custom.cc b/snapshot/mac/process_types/custom.cc index 3d5976cc..3ca5646c 100644 --- a/snapshot/mac/process_types/custom.cc +++ b/snapshot/mac/process_types/custom.cc @@ -23,9 +23,9 @@ #include "base/logging.h" #include "base/numerics/safe_math.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "snapshot/mac/process_types/internal.h" -#include "util/misc/arraysize.h" #include "util/process/process_memory_mac.h" #if !DOXYGEN @@ -145,8 +145,8 @@ size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion( sizeof(dyld_all_image_infos<Traits>), // 16 }; - if (version >= ArraySize(kSizeForVersion)) { - return kSizeForVersion[ArraySize(kSizeForVersion) - 1]; + if (version >= base::size(kSizeForVersion)) { + return kSizeForVersion[base::size(kSizeForVersion) - 1]; } static_assert(std::is_unsigned<decltype(version)>::value, diff --git a/snapshot/mac/process_types_test.cc b/snapshot/mac/process_types_test.cc index 9a9dc9d4..2ab3034c 100644 --- a/snapshot/mac/process_types_test.cc +++ b/snapshot/mac/process_types_test.cc @@ -20,13 +20,13 @@ #include <vector> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/mac/process_types/internal.h" #include "test/mac/dyld.h" #include "util/mac/mac_util.h" -#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/misc/implicit_cast.h" @@ -147,7 +147,7 @@ TEST(ProcessTypes, DyldImagesSelf) { {15, 164, 304}, {16, 176, 320}, }; - for (size_t index = 0; index < ArraySize(kVersionsAndSizes); ++index) { + for (size_t index = 0; index < base::size(kVersionsAndSizes); ++index) { uint32_t version = kVersionsAndSizes[index].version; SCOPED_TRACE(base::StringPrintf("index %zu, version %u", index, version)); @@ -268,7 +268,7 @@ TEST(ProcessTypes, DyldImagesSelf) { self_image_infos->sharedCacheBaseAddress); EXPECT_EQ(proctype_image_infos.dyldPath, reinterpret_cast<uint64_t>(self_image_infos->dyldPath)); - for (size_t index = 0; index < ArraySize(self_image_infos->notifyPorts); + for (size_t index = 0; index < base::size(self_image_infos->notifyPorts); ++index) { EXPECT_EQ(proctype_image_infos.notifyPorts[index], self_image_infos->notifyPorts[index]) @@ -288,7 +288,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 < ArraySize(proctype_image_infos.reserved); + for (size_t index = 0; index < base::size(proctype_image_infos.reserved); ++index) { EXPECT_EQ(proctype_image_infos.reserved[index], implicit_cast<uint64_t>(self_image_infos->reserved[index])) diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 47876036..f4b611d4 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -21,6 +21,7 @@ #include <memory> #include "base/numerics/safe_math.h" +#include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.h" #include "minidump/minidump_context.h" @@ -28,7 +29,6 @@ #include "snapshot/minidump/minidump_annotation_reader.h" #include "snapshot/module_snapshot.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" #include "util/misc/pdb_structures.h" namespace crashpad { @@ -859,27 +859,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 < ArraySize(minidump_context.vector_register); i++) { + for (size_t i = 0; i < base::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 < ArraySize(minidump_context.fxsave.reserved_4); i++) { + for (uint8_t i = 0; i < base::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 < ArraySize(minidump_context.fxsave.st_mm); i++) { + for (size_t i = 0; i < base::size(minidump_context.fxsave.st_mm); i++) { for (uint8_t j = 0; - j < ArraySize(minidump_context.fxsave.st_mm[0].mm_value); + j < base::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 < ArraySize(minidump_context.fxsave.xmm); i++) { - for (uint8_t j = 0; j < ArraySize(minidump_context.fxsave.xmm[0]); j++) { + 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++) { minidump_context.fxsave.xmm[i][j] = j + 1; } } @@ -962,20 +962,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 < ArraySize(ctx->fxsave.reserved_4); i++) { + for (uint8_t i = 0; i < base::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 < ArraySize(ctx->fxsave.st_mm); i++) { - for (uint8_t j = 0; j < ArraySize(ctx->fxsave.st_mm[0].mm_value); j++) { + 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++) { 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 < ArraySize(ctx->fxsave.xmm); i++) { - for (uint8_t j = 0; j < ArraySize(ctx->fxsave.xmm[0]); j++) { + 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++) { EXPECT_EQ(ctx->fxsave.xmm[i][j], j + 1); } } diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc index 46ae97a0..e77bab8b 100644 --- a/snapshot/minidump/thread_snapshot_minidump.cc +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -17,8 +17,8 @@ #include <stddef.h> #include <string.h> +#include "base/stl_util.h" #include "minidump/minidump_context.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace internal { @@ -193,7 +193,7 @@ bool ThreadSnapshotMinidump::InitializeContext( return false; } - for (size_t i = 0; i < ArraySize(src->regs); i++) { + for (size_t i = 0; i < base::size(src->regs); i++) { context_.arm->regs[i] = src->regs[i]; } @@ -205,7 +205,7 @@ bool ThreadSnapshotMinidump::InitializeContext( context_.arm->cpsr = src->cpsr; context_.arm->vfp_regs.fpscr = src->fpscr; - for (size_t i = 0; i < ArraySize(src->vfp); i++) { + for (size_t i = 0; i < base::size(src->vfp); i++) { context_.arm->vfp_regs.vfp[i] = src->vfp[i]; } @@ -225,14 +225,14 @@ bool ThreadSnapshotMinidump::InitializeContext( return false; } - for (size_t i = 0; i < ArraySize(src->regs); i++) { + for (size_t i = 0; i < base::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 < ArraySize(src->fpsimd); i++) { + for (size_t i = 0; i < base::size(src->fpsimd); i++) { context_.arm64->fpsimd[i] = src->fpsimd[i]; } @@ -255,7 +255,7 @@ bool ThreadSnapshotMinidump::InitializeContext( return false; } - for (size_t i = 0; i < ArraySize(src->regs); i++) { + for (size_t i = 0; i < base::size(src->regs); i++) { context_.mipsel->regs[i] = src->regs[i]; } @@ -263,7 +263,7 @@ bool ThreadSnapshotMinidump::InitializeContext( context_.mipsel->mdlo = static_cast<uint32_t>(src->mdlo); context_.mipsel->dsp_control = src->dsp_control; - for (size_t i = 0; i < ArraySize(src->hi); i++) { + for (size_t i = 0; i < base::size(src->hi); i++) { context_.mipsel->hi[i] = src->hi[i]; context_.mipsel->lo[i] = src->lo[i]; } @@ -292,7 +292,7 @@ bool ThreadSnapshotMinidump::InitializeContext( return false; } - for (size_t i = 0; i < ArraySize(src->regs); i++) { + for (size_t i = 0; i < base::size(src->regs); i++) { context_.mips64->regs[i] = src->regs[i]; } @@ -300,7 +300,7 @@ bool ThreadSnapshotMinidump::InitializeContext( context_.mips64->mdlo = src->mdlo; context_.mips64->dsp_control = src->dsp_control; - for (size_t i = 0; i < ArraySize(src->hi); i++) { + for (size_t i = 0; i < base::size(src->hi); i++) { context_.mips64->hi[i] = src->hi[i]; context_.mips64->lo[i] = src->lo[i]; } diff --git a/snapshot/posix/timezone.cc b/snapshot/posix/timezone.cc index 8b2b8221..9451e11f 100644 --- a/snapshot/posix/timezone.cc +++ b/snapshot/posix/timezone.cc @@ -18,8 +18,8 @@ #include <time.h> #include "base/logging.h" +#include "base/stl_util.h" #include "build/build_config.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace internal { @@ -60,7 +60,8 @@ 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 < ArraySize(kMonthDeltas) && !found_transition; + for (size_t index = 0; + index < base::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 1bb19c4e..b4405bad 100644 --- a/snapshot/posix/timezone_test.cc +++ b/snapshot/posix/timezone_test.cc @@ -22,10 +22,10 @@ #include "base/logging.h" #include "base/macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/errors.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -155,7 +155,7 @@ TEST(TimeZone, Basic) { {"UTC", false, 0, 0, "UTC", "UTC"}, }; - for (size_t index = 0; index < ArraySize(kTestTimeZones); ++index) { + for (size_t index = 0; index < base::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/sanitization_information_test.cc b/snapshot/sanitized/sanitization_information_test.cc index c7d836a5..e426f28b 100644 --- a/snapshot/sanitized/sanitization_information_test.cc +++ b/snapshot/sanitized/sanitization_information_test.cc @@ -14,9 +14,9 @@ #include "snapshot/sanitized/sanitization_information.h" +#include "base/stl_util.h" #include "build/build_config.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_linux.h" @@ -60,8 +60,8 @@ const char* const kNonEmptyWhitelist[] = {"string1", TEST_F(WhitelistTest, NonEmptyWhitelist) { ASSERT_TRUE(ReadWhitelist(kNonEmptyWhitelist)); - ASSERT_EQ(whitelist_.size(), ArraySize(kNonEmptyWhitelist) - 1); - for (size_t index = 0; index < ArraySize(kNonEmptyWhitelist) - 1; ++index) { + ASSERT_EQ(whitelist_.size(), base::size(kNonEmptyWhitelist) - 1); + for (size_t index = 0; index < base::size(kNonEmptyWhitelist) - 1; ++index) { EXPECT_EQ(whitelist_[index], kNonEmptyWhitelist[index]); } } diff --git a/snapshot/test/test_cpu_context.cc b/snapshot/test/test_cpu_context.cc index 7694d7eb..746e3407 100644 --- a/snapshot/test/test_cpu_context.cc +++ b/snapshot/test/test_cpu_context.cc @@ -17,7 +17,7 @@ #include <string.h> #include <sys/types.h> -#include "util/misc/arraysize.h" +#include "base/stl_util.h" namespace crashpad { namespace test { @@ -44,28 +44,28 @@ void InitializeCPUContextFxsave(FxsaveType* fxsave, uint32_t* seed) { fxsave->reserved_3 = static_cast<uint16_t>(value++); fxsave->mxcsr = value++; fxsave->mxcsr_mask = value++; - for (size_t st_mm_index = 0; st_mm_index < ArraySize(fxsave->st_mm); + for (size_t st_mm_index = 0; st_mm_index < base::size(fxsave->st_mm); ++st_mm_index) { - for (size_t byte = 0; byte < ArraySize(fxsave->st_mm[st_mm_index].st); + for (size_t byte = 0; byte < base::size(fxsave->st_mm[st_mm_index].st); ++byte) { fxsave->st_mm[st_mm_index].st[byte] = static_cast<uint8_t>(value++); } for (size_t byte = 0; - byte < ArraySize(fxsave->st_mm[st_mm_index].st_reserved); + byte < base::size(fxsave->st_mm[st_mm_index].st_reserved); ++byte) { fxsave->st_mm[st_mm_index].st_reserved[byte] = static_cast<uint8_t>(value); } } - for (size_t xmm_index = 0; xmm_index < ArraySize(fxsave->xmm); ++xmm_index) { - for (size_t byte = 0; byte < ArraySize(fxsave->xmm[xmm_index]); ++byte) { + 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) { fxsave->xmm[xmm_index][byte] = static_cast<uint8_t>(value++); } } - for (size_t byte = 0; byte < ArraySize(fxsave->reserved_4); ++byte) { + for (size_t byte = 0; byte < base::size(fxsave->reserved_4); ++byte) { fxsave->reserved_4[byte] = static_cast<uint8_t>(value++); } - for (size_t byte = 0; byte < ArraySize(fxsave->available); ++byte) { + for (size_t byte = 0; byte < base::size(fxsave->available); ++byte) { fxsave->available[byte] = static_cast<uint8_t>(value++); } @@ -174,7 +174,7 @@ void InitializeCPUContextARM(CPUContext* context, uint32_t seed) { uint32_t value = seed; - for (size_t index = 0; index < ArraySize(arm->regs); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(arm->vfp_regs.vfp); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(arm64->regs); ++index) { + for (size_t index = 0; index < base::size(arm64->regs); ++index) { arm64->regs[index] = value++; } arm64->sp = value++; arm64->pc = value++; arm64->spsr = value++; - for (size_t index = 0; index < ArraySize(arm64->fpsimd); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(mipsel->regs); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(mipsel->fpregs.fregs); ++index) { + for (size_t index = 0; index < base::size(mipsel->fpregs.fregs); ++index) { mipsel->fpregs.fregs[index]._fp_fregs = static_cast<float>(value++); } @@ -267,7 +267,7 @@ void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed) { uint64_t value = seed; - for (size_t index = 0; index < ArraySize(mips64->regs); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(mips64->fpregs.dregs); ++index) { + for (size_t index = 0; index < base::size(mips64->fpregs.dregs); ++index) { mips64->fpregs.dregs[index] = static_cast<double>(value++); } diff --git a/snapshot/win/cpu_context_win_test.cc b/snapshot/win/cpu_context_win_test.cc index 7f66f9d3..e63f04e5 100644 --- a/snapshot/win/cpu_context_win_test.cc +++ b/snapshot/win/cpu_context_win_test.cc @@ -16,11 +16,11 @@ #include <windows.h> +#include "base/stl_util.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/cpu_context.h" #include "test/hex_string.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -87,13 +87,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, - ArraySize(cpu_context_x86.fxsave.st_mm[st_mm].st)), - std::string(ArraySize(cpu_context_x86.fxsave.st_mm[st_mm].st) * 2, + 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, '0')) << "st_mm " << st_mm; } EXPECT_EQ(BytesToHexString(cpu_context_x86.fxsave.st_mm[7].st, - ArraySize(cpu_context_x86.fxsave.st_mm[7].st)), + base::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 e6a9e5d6..8bccbd62 100644 --- a/snapshot/win/crashpad_snapshot_test_image_reader.cc +++ b/snapshot/win/crashpad_snapshot_test_image_reader.cc @@ -15,9 +15,9 @@ #include <windows.h> #include "base/logging.h" +#include "base/stl_util.h" #include "client/crashpad_info.h" #include "util/file/file_io.h" -#include "util/misc/arraysize.h" #include "util/synchronization/semaphore.h" #include "util/win/scoped_handle.h" @@ -29,7 +29,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 < ArraySize(pointers); ++i) { + for (size_t i = 0; i < base::size(pointers); ++i) { pointers[i] = new int[2048]; } @@ -53,7 +53,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 < ArraySize(threads); ++i) { + for (size_t i = 0; i < base::size(threads); ++i) { threads[i].reset(CreateThread(nullptr, 0, &LotsOfReferencesThreadProc, @@ -66,7 +66,7 @@ int wmain(int argc, wchar_t* argv[]) { } } - for (size_t i = 0; i < ArraySize(threads); ++i) { + for (size_t i = 0; i < base::size(threads); ++i) { semaphore.Wait(); } diff --git a/snapshot/win/pe_image_annotations_reader.cc b/snapshot/win/pe_image_annotations_reader.cc index c5e53735..058342db 100644 --- a/snapshot/win/pe_image_annotations_reader.cc +++ b/snapshot/win/pe_image_annotations_reader.cc @@ -17,13 +17,13 @@ #include <string.h> #include <sys/types.h> +#include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" #include "client/annotation.h" #include "client/simple_string_dictionary.h" #include "snapshot/snapshot_constants.h" #include "snapshot/win/pe_image_reader.h" #include "snapshot/win/process_reader_win.h" -#include "util/misc/arraysize.h" #include "util/win/process_structs.h" namespace crashpad { @@ -156,7 +156,8 @@ void PEImageAnnotationsReader::ReadCrashpadAnnotationsList( snapshot.type = current.type; char name[Annotation::kNameMaxLength]; - if (!process_reader_->Memory()->Read(current.name, ArraySize(name), name)) { + if (!process_reader_->Memory()->Read( + current.name, base::size(name), name)) { LOG(WARNING) << "could not read annotation name at index " << index << " in " << base::UTF16ToUTF8(name_); continue; diff --git a/snapshot/win/pe_image_reader.cc b/snapshot/win/pe_image_reader.cc index b4b1d169..e69faef0 100644 --- a/snapshot/win/pe_image_reader.cc +++ b/snapshot/win/pe_image_reader.cc @@ -21,10 +21,10 @@ #include <memory> #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "client/crashpad_info.h" #include "snapshot/win/pe_image_resource_reader.h" -#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/misc/pdb_structures.h" #include "util/win/process_structs.h" @@ -288,7 +288,7 @@ bool PEImageReader::VSFixedFileInfo( version_info.wType != 0 || wcsncmp(version_info.szKey, L"VS_VERSION_INFO", - ArraySize(version_info.szKey)) != 0) { + base::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 eca6f486..1880c871 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -17,9 +17,9 @@ #include <windows.h> #include <string.h> +#include "base/stl_util.h" #include "gtest/gtest.h" #include "test/win/win_multiprocess.h" -#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/synchronization/semaphore.h" #include "util/thread/thread.h" @@ -44,7 +44,7 @@ TEST(ProcessReaderWin, SelfBasic) { EXPECT_EQ(process_reader.GetProcessInfo().ProcessID(), GetCurrentProcessId()); static constexpr char kTestMemory[] = "Some test memory"; - char buffer[ArraySize(kTestMemory)]; + char buffer[base::size(kTestMemory)]; ASSERT_TRUE(process_reader.Memory()->Read( reinterpret_cast<uintptr_t>(kTestMemory), sizeof(kTestMemory), &buffer)); EXPECT_STREQ(kTestMemory, buffer); @@ -185,7 +185,7 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { // the pipe. CheckedReadFileAtEOF(ReadPipeHandle()); - for (size_t i = 0; i < ArraySize(threads); ++i) + for (size_t i = 0; i < base::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 5d98a5f7..f91ef29b 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -22,9 +22,9 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" +#include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" -#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/misc/time.h" #include "util/win/nt_internals.h" @@ -335,7 +335,7 @@ void ProcessSnapshotWin::InitializeUnloadedModules() { uet.TimeDateStamp, base::UTF16ToUTF8(base::StringPiece16( uet.ImageName, - wcsnlen(uet.ImageName, ArraySize(uet.ImageName)))))); + wcsnlen(uet.ImageName, base::size(uet.ImageName)))))); } } } @@ -535,9 +535,9 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock( env_block.resize( static_cast<unsigned int>(bytes_read / sizeof(env_block[0]))); static constexpr wchar_t terminator[] = {0, 0}; - size_t at = env_block.find(std::wstring(terminator, ArraySize(terminator))); + size_t at = env_block.find(std::wstring(terminator, base::size(terminator))); if (at != std::wstring::npos) - env_block.resize(at + ArraySize(terminator)); + env_block.resize(at + base::size(terminator)); return env_block.size() * sizeof(env_block[0]); } diff --git a/test/hex_string.h b/test/hex_string.h index 2d7801b9..b0d44531 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, ArraySize(observed)), -//! BytesToHexString(expected, ArraySize(expected))); +//! EXPECT_EQ(BytesToHexString(observed, base::size(observed)), +//! BytesToHexString(expected, base::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 3d44cc9f..3a09eb76 100644 --- a/test/hex_string_test.cc +++ b/test/hex_string_test.cc @@ -14,8 +14,8 @@ #include "test/hex_string.h" +#include "base/stl_util.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -25,7 +25,7 @@ TEST(HexString, HexString) { EXPECT_EQ(BytesToHexString(nullptr, 0), ""); static constexpr char kBytes[] = "Abc123xyz \x0a\x7f\xf0\x9f\x92\xa9_"; - EXPECT_EQ(BytesToHexString(kBytes, ArraySize(kBytes)), + EXPECT_EQ(BytesToHexString(kBytes, base::size(kBytes)), "41626331323378797a200a7ff09f92a95f00"); } diff --git a/tools/crashpad_database_util.cc b/tools/crashpad_database_util.cc index d8274c56..17a4771d 100644 --- a/tools/crashpad_database_util.cc +++ b/tools/crashpad_database_util.cc @@ -29,6 +29,7 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" +#include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "client/crash_report_database.h" @@ -36,7 +37,6 @@ #include "tools/tool_support.h" #include "util/file/file_io.h" #include "util/file/file_reader.h" -#include "util/misc/arraysize.h" #include "util/misc/uuid.h" #include "util/stdlib/string_number_conversion.h" @@ -109,14 +109,14 @@ bool StringToBool(const char* string, bool* boolean) { "set", }; - for (size_t index = 0; index < ArraySize(kFalseWords); ++index) { + for (size_t index = 0; index < base::size(kFalseWords); ++index) { if (strcasecmp(string, kFalseWords[index]) == 0) { *boolean = false; return true; } } - for (size_t index = 0; index < ArraySize(kTrueWords); ++index) { + for (size_t index = 0; index < base::size(kTrueWords); ++index) { if (strcasecmp(string, kTrueWords[index]) == 0) { *boolean = true; return true; @@ -159,7 +159,7 @@ bool StringToTime(const char* string, time_t* out_time, bool utc) { "%+", }; - for (size_t index = 0; index < ArraySize(kFormats); ++index) { + for (size_t index = 0; index < base::size(kFormats); ++index) { tm time_tm; const char* strptime_result = strptime(string, kFormats[index], &time_tm); if (strptime_result == end) { @@ -214,7 +214,7 @@ std::string TimeToString(time_t out_time, bool utc) { char string[64]; CHECK_NE( - strftime(string, ArraySize(string), "%Y-%m-%d %H:%M:%S %Z", &time_tm), + strftime(string, base::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 2a8678f0..2275adef 100644 --- a/util/file/delimited_file_reader.cc +++ b/util/file/delimited_file_reader.cc @@ -21,7 +21,7 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" -#include "util/misc/arraysize.h" +#include "base/stl_util.h" namespace crashpad { @@ -76,7 +76,7 @@ DelimitedFileReader::Result DelimitedFileReader::GetDelim(char delimiter, return Result::kEndOfFile; } - DCHECK_LE(static_cast<size_t>(read_result), ArraySize(buf_)); + DCHECK_LE(static_cast<size_t>(read_result), base::size(buf_)); DCHECK( base::IsValueInRangeForNumericType<decltype(buf_len_)>(read_result)); buf_len_ = static_cast<decltype(buf_len_)>(read_result); diff --git a/util/file/delimited_file_reader_test.cc b/util/file/delimited_file_reader_test.cc index b226f3d0..a2fd7d5c 100644 --- a/util/file/delimited_file_reader_test.cc +++ b/util/file/delimited_file_reader_test.cc @@ -17,10 +17,10 @@ #include <vector> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/file/string_file.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -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, ArraySize(kString) - 1)); + string_file.SetString(std::string(kString, base::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, ArraySize(kString) - 1)); + string_file.SetString(std::string(kString, base::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 < ArraySize(kSizes); ++index) { + for (size_t index = 0; index < base::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 d341a5d8..0fdd25c4 100644 --- a/util/file/file_io_test.cc +++ b/util/file/file_io_test.cc @@ -22,12 +22,12 @@ #include "base/atomicops.h" #include "base/files/file_path.h" #include "base/macros.h" +#include "base/stl_util.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "test/errors.h" #include "test/file.h" #include "test/scoped_temp_dir.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/thread/thread.h" @@ -613,7 +613,7 @@ void LockingTest(FileLocking main_lock, FileLocking other_locks) { LockingTestThread threads[20]; int expected_iterations = 0; - for (size_t index = 0; index < ArraySize(threads); ++index) { + for (size_t index = 0; index < base::size(threads); ++index) { int iterations_for_this_thread = static_cast<int>(index * 10); threads[index].Init( (other_locks == FileLocking::kShared) diff --git a/util/linux/direct_ptrace_connection.cc b/util/linux/direct_ptrace_connection.cc index 371bed2e..e757d8f5 100644 --- a/util/linux/direct_ptrace_connection.cc +++ b/util/linux/direct_ptrace_connection.cc @@ -19,10 +19,10 @@ #include <utility> #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "util/file/directory_reader.h" #include "util/file/file_io.h" -#include "util/misc/arraysize.h" #include "util/misc/as_underlying_type.h" namespace crashpad { @@ -93,7 +93,7 @@ bool DirectPtraceConnection::Threads(std::vector<pid_t>* threads) { DCHECK(threads->empty()); char path[32]; - snprintf(path, ArraySize(path), "/proc/%d/task", pid_); + snprintf(path, base::size(path), "/proc/%d/task", pid_); DirectoryReader reader; if (!reader.Open(base::FilePath(path))) { return false; diff --git a/util/linux/proc_stat_reader.cc b/util/linux/proc_stat_reader.cc index 60f10546..88658f58 100644 --- a/util/linux/proc_stat_reader.cc +++ b/util/linux/proc_stat_reader.cc @@ -20,8 +20,8 @@ #include "base/files/file_path.h" #include "base/logging.h" +#include "base/stl_util.h" #include "util/file/file_io.h" -#include "util/misc/arraysize.h" #include "util/misc/lexing.h" #include "util/misc/time.h" @@ -48,7 +48,7 @@ bool ProcStatReader::Initialize(PtraceConnection* connection, pid_t tid) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); char path[32]; - snprintf(path, ArraySize(path), "/proc/%d/stat", tid); + snprintf(path, base::size(path), "/proc/%d/stat", tid); if (!connection->ReadFileContents(base::FilePath(path), &contents_)) { return false; } diff --git a/util/linux/ptrace_client.cc b/util/linux/ptrace_client.cc index e8afaa4e..d822d10e 100644 --- a/util/linux/ptrace_client.cc +++ b/util/linux/ptrace_client.cc @@ -20,10 +20,10 @@ #include <string> #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "util/file/file_io.h" #include "util/linux/ptrace_broker.h" -#include "util/misc/arraysize.h" #include "util/process/process_memory_linux.h" namespace crashpad { @@ -271,7 +271,7 @@ bool PtraceClient::Threads(std::vector<pid_t>* threads) { threads->push_back(pid_); char path[32]; - snprintf(path, ArraySize(path), "/proc/%d/task", pid_); + snprintf(path, base::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 f2f8f548..85313795 100644 --- a/util/mac/checked_mach_address_range_test.cc +++ b/util/mac/checked_mach_address_range_test.cc @@ -19,10 +19,10 @@ #include <limits> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -116,7 +116,7 @@ TEST(CheckedMachAddressRange, IsValid) { {0xffffffffffffffff, 1, kInvalid}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 4a6402dc..b793a9b9 100644 --- a/util/mac/launchd_test.mm +++ b/util/mac/launchd_test.mm @@ -23,8 +23,8 @@ #include <limits> #include "base/mac/scoped_launch_data.h" +#include "base/stl_util.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" #include "util/stdlib/objc.h" namespace crashpad { @@ -58,7 +58,7 @@ TEST(Launchd, CFPropertyToLaunchData_Integer) { @0xfedcba9876543210, }; - for (size_t index = 0; index < ArraySize(integer_nses); ++index) { + for (size_t index = 0; index < base::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 @@ TEST(Launchd, CFPropertyToLaunchData_FloatingPoint) { [NSNumber numberWithDouble:std::numeric_limits<double>::signaling_NaN()], }; - for (size_t index = 0; index < ArraySize(double_nses); ++index) { + for (size_t index = 0; index < base::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 @@ TEST(Launchd, CFPropertyToLaunchData_Boolean) { @YES, }; - for (size_t index = 0; index < ArraySize(bool_nses); ++index) { + for (size_t index = 0; index < base::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 @@ TEST(Launchd, CFPropertyToLaunchData_String) { @"Üñîçø∂é", }; - for (size_t index = 0; index < ArraySize(string_nses); ++index) { + for (size_t index = 0; index < base::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 721e560e..a1918c02 100644 --- a/util/mach/child_port_handshake.cc +++ b/util/mach/child_port_handshake.cc @@ -31,6 +31,7 @@ #include "base/mac/scoped_mach_port.h" #include "base/posix/eintr_wrapper.h" #include "base/rand_util.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "util/file/file_io.h" #include "util/mach/child_port.h" @@ -38,7 +39,6 @@ #include "util/mach/mach_extensions.h" #include "util/mach/mach_message.h" #include "util/mach/mach_message_server.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/misc/random_string.h" @@ -158,8 +158,8 @@ mach_port_t ChildPortHandshakeServer::RunServer( 0, 0, nullptr); - int rv = HANDLE_EINTR( - kevent(kq.get(), changelist, ArraySize(changelist), nullptr, 0, nullptr)); + int rv = HANDLE_EINTR(kevent( + kq.get(), changelist, base::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 678d3b29..aa7a1b8b 100644 --- a/util/mach/child_port_server.cc +++ b/util/mach/child_port_server.cc @@ -15,9 +15,9 @@ #include "util/mach/child_port_server.h" #include "base/logging.h" +#include "base/stl_util.h" #include "util/mach/child_portServer.h" #include "util/mach/mach_message.h" -#include "util/misc/arraysize.h" namespace { @@ -91,7 +91,7 @@ std::set<mach_msg_id_t> ChildPortServer::MachMessageServerRequestIDs() { static constexpr mach_msg_id_t request_ids[] = {kMachMessageIDChildPortCheckIn}; return std::set<mach_msg_id_t>(&request_ids[0], - &request_ids[ArraySize(request_ids)]); + &request_ids[base::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 c2ed5d79..87242be3 100644 --- a/util/mach/composite_mach_message_server_test.cc +++ b/util/mach/composite_mach_message_server_test.cc @@ -16,11 +16,11 @@ #include <sys/types.h> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/gtest_death.h" #include "util/mach/mach_message.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -197,7 +197,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { TestMachMessageHandler handlers[3]; std::set<mach_msg_id_t> expect_request_ids; - for (size_t index = 0; index < ArraySize(kRequestIDs0); ++index) { + for (size_t index = 0; index < base::size(kRequestIDs0); ++index) { const mach_msg_id_t request_id = kRequestIDs0[index]; handlers[0].AddRequestID(request_id); expect_request_ids.insert(request_id); @@ -206,7 +206,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { handlers[0].SetReplySize(sizeof(mig_reply_error_t)); handlers[0].SetReturnCodes(true, kReturnCode0, false); - for (size_t index = 0; index < ArraySize(kRequestIDs1); ++index) { + for (size_t index = 0; index < base::size(kRequestIDs1); ++index) { const mach_msg_id_t request_id = kRequestIDs1[index]; handlers[1].AddRequestID(request_id); expect_request_ids.insert(request_id); @@ -215,7 +215,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { handlers[1].SetReplySize(200); handlers[1].SetReturnCodes(false, kReturnCode1, true); - for (size_t index = 0; index < ArraySize(kRequestIDs2); ++index) { + for (size_t index = 0; index < base::size(kRequestIDs2); ++index) { const mach_msg_id_t request_id = kRequestIDs2[index]; handlers[2].AddRequestID(request_id); expect_request_ids.insert(request_id); @@ -253,7 +253,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { // Send messages with known request IDs. - for (size_t index = 0; index < ArraySize(kRequestIDs0); ++index) { + for (size_t index = 0; index < base::size(kRequestIDs0); ++index) { request.header.msgh_id = kRequestIDs0[index]; SCOPED_TRACE(base::StringPrintf( "handler 0, index %zu, id %d", index, request.header.msgh_id)); @@ -264,7 +264,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { EXPECT_FALSE(destroy_complex_request); } - for (size_t index = 0; index < ArraySize(kRequestIDs1); ++index) { + for (size_t index = 0; index < base::size(kRequestIDs1); ++index) { request.header.msgh_id = kRequestIDs1[index]; SCOPED_TRACE(base::StringPrintf( "handler 1, index %zu, id %d", index, request.header.msgh_id)); @@ -275,7 +275,7 @@ TEST(CompositeMachMessageServer, ThreeHandlers) { EXPECT_TRUE(destroy_complex_request); } - for (size_t index = 0; index < ArraySize(kRequestIDs2); ++index) { + for (size_t index = 0; index < base::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 7d1d00da..007442ab 100644 --- a/util/mach/exc_client_variants_test.cc +++ b/util/mach/exc_client_variants_test.cc @@ -20,6 +20,7 @@ #include <sys/types.h> #include "base/macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" @@ -29,7 +30,6 @@ #include "util/mach/mach_extensions.h" #include "util/mach/mach_message.h" #include "util/mach/mach_message_server.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -182,11 +182,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 < ArraySize(old_state); ++index) { + for (size_t index = 0; index < base::size(old_state); ++index) { old_state[index] = index; } old_state_p = reinterpret_cast<thread_state_t>(&old_state); - old_state_count = ArraySize(old_state); + old_state_count = base::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 @@ -203,7 +203,7 @@ class TestExcClientVariants : public MachMultiprocess, task, exception, code, - ArraySize(code), + base::size(code), flavor_p, old_state_p, old_state_count, @@ -274,7 +274,7 @@ TEST(ExcClientVariants, UniversalExceptionRaise) { kMachExceptionCodes | EXCEPTION_STATE_IDENTITY, }; - for (size_t index = 0; index < ArraySize(kBehaviors); ++index) { + for (size_t index = 0; index < base::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 f7b0b3d6..6264cb33 100644 --- a/util/mach/exc_server_variants.cc +++ b/util/mach/exc_server_variants.cc @@ -21,6 +21,7 @@ #include <vector> #include "base/logging.h" +#include "base/stl_util.h" #include "util/mac/mac_util.h" #include "util/mach/composite_mach_message_server.h" #include "util/mach/exc.h" @@ -29,7 +30,6 @@ #include "util/mach/mach_exc.h" #include "util/mach/mach_excServer.h" #include "util/mach/mach_message.h" -#include "util/misc/arraysize.h" namespace crashpad { @@ -243,7 +243,7 @@ class ExcServer : public MachMessageServer::Interface { Traits::kMachMessageIDExceptionRaiseStateIdentity, }; return std::set<mach_msg_id_t>(&request_ids[0], - &request_ids[ArraySize(request_ids)]); + &request_ids[base::size(request_ids)]); } mach_msg_size_t MachMessageServerRequestSize() override { @@ -320,7 +320,7 @@ bool ExcServer<Traits>::MachMessageServerFunction( using Reply = typename Traits::ExceptionRaiseStateReply; Reply* out_reply = reinterpret_cast<Reply*>(out_header); out_reply->flavor = in_request_1->flavor; - out_reply->new_stateCnt = ArraySize(out_reply->new_state); + out_reply->new_stateCnt = base::size(out_reply->new_state); out_reply->RetCode = interface_->CatchExceptionRaiseState(in_header->msgh_local_port, in_request->exception, @@ -363,7 +363,7 @@ bool ExcServer<Traits>::MachMessageServerFunction( using Reply = typename Traits::ExceptionRaiseStateIdentityReply; Reply* out_reply = reinterpret_cast<Reply*>(out_header); out_reply->flavor = in_request_1->flavor; - out_reply->new_stateCnt = ArraySize(out_reply->new_state); + out_reply->new_stateCnt = base::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 b50ded14..078d4aed 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -19,6 +19,7 @@ #include <string.h> #include <sys/types.h> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gmock/gmock.h" @@ -29,7 +30,6 @@ #include "util/mach/exception_behaviors.h" #include "util/mach/exception_types.h" #include "util/mach/mach_message.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -229,7 +229,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, ArraySize(new_state)); + EXPECT_EQ(new_stateCnt, base::size(new_state)); } mach_msg_header_t Head; @@ -660,7 +660,7 @@ TEST(ExcServerVariants, MockExceptionRaiseState) { AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(ArraySize(reply.new_state)), + IsThreadStateAndCount(base::size(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -709,7 +709,7 @@ TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) { AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(ArraySize(reply.new_state)), + IsThreadStateAndCount(base::size(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -803,7 +803,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseState) { kTestMachExceptionCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(ArraySize(reply.new_state)), + IsThreadStateAndCount(base::size(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -853,7 +853,7 @@ TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) { kTestMachExceptionCodes[1]), Pointee(Eq(kThreadStateFlavor)), IsThreadStateAndCount(kThreadStateFlavorCount), - IsThreadStateAndCount(ArraySize(reply.new_state)), + IsThreadStateAndCount(base::size(reply.new_state)), Eq(request.Trailer()))) .WillOnce(Return(KERN_SUCCESS)) .RetiresOnSaturation(); @@ -907,7 +907,7 @@ TEST(ExcServerVariants, MockUnknownID) { 2508, }; - for (size_t index = 0; index < ArraySize(unknown_ids); ++index) { + for (size_t index = 0; index < base::size(unknown_ids); ++index) { mach_msg_id_t id = unknown_ids[index]; SCOPED_TRACE(base::StringPrintf("unknown id %d", id)); @@ -1180,7 +1180,7 @@ TEST(ExcServerVariants, ThreadStates) { #endif }; - for (size_t index = 0; index < ArraySize(test_data); ++index) { + for (size_t index = 0; index < base::size(test_data); ++index) { const auto& test = test_data[index]; SCOPED_TRACE( base::StringPrintf("index %zu, flavor %d", index, test.flavor)); @@ -1253,7 +1253,7 @@ TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) { KERN_SUCCESS}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::size(kTestData); ++index) { const auto& test_data = kTestData[index]; SCOPED_TRACE( base::StringPrintf("index %zu, behavior %d, set_thread_state %s", @@ -1272,8 +1272,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 = ArraySize(old_state); - mach_msg_type_number_t new_state_count = ArraySize(new_state); + 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); // EXCEPTION_DEFAULT (with or without MACH_EXCEPTION_CODES) is not // state-carrying. new_state and new_state_count should be untouched. @@ -1282,8 +1282,8 @@ TEST(ExcServerVariants, ExcServerCopyState) { old_state_count, new_state, &new_state_count); - EXPECT_EQ(new_state_count, ArraySize(new_state)); - for (size_t i = 0; i < ArraySize(new_state); ++i) { + EXPECT_EQ(new_state_count, base::size(new_state)); + for (size_t i = 0; i < base::size(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } @@ -1292,8 +1292,8 @@ TEST(ExcServerVariants, ExcServerCopyState) { old_state_count, new_state, &new_state_count); - EXPECT_EQ(new_state_count, ArraySize(new_state)); - for (size_t i = 0; i < ArraySize(new_state); ++i) { + EXPECT_EQ(new_state_count, base::size(new_state)); + for (size_t i = 0; i < base::size(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } @@ -1305,7 +1305,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 < ArraySize(new_state); ++i) { + for (size_t i = copy_limit; i < base::size(new_state); ++i) { EXPECT_EQ(new_state[i], 0u) << "i " << i; } @@ -1321,23 +1321,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 < ArraySize(new_state); ++i) { + for (size_t i = copy_limit; i < base::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 = ArraySize(new_state); + new_state_count = base::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 < ArraySize(old_state); ++i) { + for (size_t i = 0; i < base::size(old_state); ++i) { EXPECT_EQ(new_state[i], old_state[i]) << "i " << i; } - for (size_t i = ArraySize(old_state); i < ArraySize(new_state); ++i) { + for (size_t i = base::size(old_state); i < base::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 fd74d22c..bdbf673a 100644 --- a/util/mach/exception_behaviors_test.cc +++ b/util/mach/exception_behaviors_test.cc @@ -16,10 +16,10 @@ #include <sys/types.h> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/mach/mach_extensions.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -53,7 +53,7 @@ TEST(ExceptionBehaviors, ExceptionBehaviors) { EXCEPTION_STATE_IDENTITY}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 030c7f30..da2c8222 100644 --- a/util/mach/exception_types_test.cc +++ b/util/mach/exception_types_test.cc @@ -20,11 +20,11 @@ #include <sys/types.h> #include <unistd.h> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/mac/mac_util.h" #include "util/mach/mach_extensions.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -67,7 +67,7 @@ TEST(ExceptionTypes, ExcCrashRecoverOriginalException) { {0, 0, 0, 0}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::size(kTestData); ++index) { const auto& test_data = kTestData[index]; SCOPED_TRACE(base::StringPrintf( "index %zu, code_0 0x%llx", index, test_data.code_0)); @@ -84,7 +84,7 @@ TEST(ExceptionTypes, ExcCrashRecoverOriginalException) { // Now make sure that ExcCrashRecoverOriginalException() properly ignores // optional arguments. - static_assert(ArraySize(kTestData) >= 1, "must have something to test"); + static_assert(base::size(kTestData) >= 1, "must have something to test"); const auto& test_data = kTestData[0]; EXPECT_EQ( ExcCrashRecoverOriginalException(test_data.code_0, nullptr, nullptr), @@ -238,7 +238,7 @@ TEST(ExceptionTypes, ExceptionCodeForMetrics) { {0x00010000, 0x00010000, static_cast<int32_t>(0xffffffff)}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 724d84e2..e3a3f94b 100644 --- a/util/mach/mach_message_server_test.cc +++ b/util/mach/mach_message_server_test.cc @@ -23,13 +23,13 @@ #include "base/mac/scoped_mach_port.h" #include "base/macros.h" +#include "base/stl_util.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" #include "test/mac/mach_multiprocess.h" #include "util/file/file_io.h" #include "util/mach/mach_extensions.h" #include "util/mach/mach_message.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" namespace crashpad { @@ -282,7 +282,7 @@ class TestMachMessageServer : public MachMessageServer::Interface, std::set<mach_msg_id_t> MachMessageServerRequestIDs() override { static constexpr mach_msg_id_t request_ids[] = {kRequestMessageID}; return std::set<mach_msg_id_t>(&request_ids[0], - &request_ids[ArraySize(request_ids)]); + &request_ids[base::size(request_ids)]); } mach_msg_size_t MachMessageServerRequestSize() override { diff --git a/util/mach/notify_server.cc b/util/mach/notify_server.cc index 5d0b3c0c..b9da7958 100644 --- a/util/mach/notify_server.cc +++ b/util/mach/notify_server.cc @@ -15,9 +15,9 @@ #include "util/mach/notify_server.h" #include "base/logging.h" +#include "base/stl_util.h" #include "util/mach/mach_message.h" #include "util/mach/notifyServer.h" -#include "util/misc/arraysize.h" namespace { @@ -228,7 +228,7 @@ std::set<mach_msg_id_t> NotifyServer::MachMessageServerRequestIDs() { MACH_NOTIFY_DEAD_NAME, }; return std::set<mach_msg_id_t>(&request_ids[0], - &request_ids[ArraySize(request_ids)]); + &request_ids[base::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 fa6eefb3..71fe1154 100644 --- a/util/mach/symbolic_constants_mach.cc +++ b/util/mach/symbolic_constants_mach.cc @@ -17,10 +17,10 @@ #include <string.h> #include <sys/types.h> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "util/mach/exception_behaviors.h" #include "util/mach/mach_extensions.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/stdlib/string_number_conversion.h" @@ -45,7 +45,7 @@ constexpr const char* kExceptionNames[] = { "GUARD", "CORPSE_NOTIFY", }; -static_assert(ArraySize(kExceptionNames) == EXC_TYPES_COUNT, +static_assert(base::size(kExceptionNames) == EXC_TYPES_COUNT, "kExceptionNames length"); constexpr char kExcPrefix[] = "EXC_"; @@ -170,7 +170,7 @@ std::string ThreadStateFlavorFullToShort(const base::StringPiece& flavor) { {"_STATE32", "32"}, {"_STATE64", "64"}, }; - for (size_t suffix_index = 0; suffix_index < ArraySize(kStateSuffixes); + for (size_t suffix_index = 0; suffix_index < base::size(kStateSuffixes); ++suffix_index) { const char* suffix = kStateSuffixes[suffix_index].orig; size_t suffix_len = strlen(suffix); @@ -194,7 +194,7 @@ namespace crashpad { std::string ExceptionToString(exception_type_t exception, SymbolicConstantToStringOptions options) { const char* exception_name = - implicit_cast<size_t>(exception) < ArraySize(kExceptionNames) + implicit_cast<size_t>(exception) < base::size(kExceptionNames) ? kExceptionNames[exception] : nullptr; if (!exception_name) { @@ -220,7 +220,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<exception_type_t>(ArraySize(kExceptionNames)); + index < implicit_cast<exception_type_t>(base::size(kExceptionNames)); ++index) { const char* exception_name = kExceptionNames[index]; if (!exception_name) { @@ -250,7 +250,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 < ArraySize(kExceptionNames); + for (size_t exception = 0; exception < base::size(kExceptionNames); ++exception) { const char* exception_name = kExceptionNames[exception]; exception_mask_t exception_mask_value = 1 << exception; @@ -324,7 +324,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<exception_type_t>(ArraySize(kExceptionNames)); + index < implicit_cast<exception_type_t>(base::size(kExceptionNames)); ++index) { const char* exception_name = kExceptionNames[index]; if (!exception_name) { @@ -363,7 +363,7 @@ std::string ExceptionBehaviorToString(exception_behavior_t behavior, const exception_behavior_t basic_behavior = ExceptionBehaviorBasic(behavior); const char* behavior_name = - implicit_cast<size_t>(basic_behavior) < ArraySize(kBehaviorNames) + implicit_cast<size_t>(basic_behavior) < base::size(kBehaviorNames) ? kBehaviorNames[basic_behavior] : nullptr; if (!behavior_name) { @@ -430,7 +430,8 @@ 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<exception_behavior_t>(ArraySize(kBehaviorNames)); + index < + implicit_cast<exception_behavior_t>(base::size(kBehaviorNames)); ++index) { const char* behavior_name = kBehaviorNames[index]; if (!behavior_name) { @@ -466,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<size_t>(flavor) < ArraySize(kFlavorNames) + implicit_cast<size_t>(flavor) < base::size(kFlavorNames) ? kFlavorNames[flavor] : nullptr; if (!flavor_name) { for (size_t generic_flavor_index = 0; - generic_flavor_index < ArraySize(kGenericFlavorNames); + generic_flavor_index < base::size(kGenericFlavorNames); ++generic_flavor_index) { if (flavor == kGenericFlavorNames[generic_flavor_index].flavor) { flavor_name = kGenericFlavorNames[generic_flavor_index].name; @@ -499,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<thread_state_flavor_t>(ArraySize(kFlavorNames)); + index < implicit_cast<thread_state_flavor_t>(base::size(kFlavorNames)); ++index) { const char* flavor_name = kFlavorNames[index]; if (!flavor_name) { @@ -519,7 +520,7 @@ bool StringToThreadStateFlavor(const base::StringPiece& string, } for (size_t generic_flavor_index = 0; - generic_flavor_index < ArraySize(kGenericFlavorNames); + generic_flavor_index < base::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 4856f0ad..e58a9c53 100644 --- a/util/mach/symbolic_constants_mach_test.cc +++ b/util/mach/symbolic_constants_mach_test.cc @@ -18,15 +18,15 @@ #include <string.h> #include <sys/types.h> +#include "base/stl_util.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/mach/mach_extensions.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #define NUL_TEST_DATA(string) \ - { string, ArraySize(string) - 1 } + { string, base::size(string) - 1 } namespace crashpad { namespace test { @@ -160,7 +160,7 @@ void TestExceptionToString(exception_type_t value, } TEST(SymbolicConstantsMach, ExceptionToString) { - for (size_t index = 0; index < ArraySize(kExceptionTestData); ++index) { + for (size_t index = 0; index < base::size(kExceptionTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestExceptionToString(kExceptionTestData[index].exception, kExceptionTestData[index].full_name, @@ -188,11 +188,11 @@ void TestStringToException(const base::StringPiece& string, } TEST(SymbolicConstantsMach, StringToException) { - for (size_t option_index = 0; option_index < ArraySize(kNormalOptions); + for (size_t option_index = 0; option_index < base::size(kNormalOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kNormalOptions[option_index]; - for (size_t index = 0; index < ArraySize(kExceptionTestData); ++index) { + for (size_t index = 0; index < base::size(kExceptionTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); exception_type_t exception = kExceptionTestData[index].exception; { @@ -230,7 +230,7 @@ TEST(SymbolicConstantsMach, StringToException) { "", }; - for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { + for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToException(kNegativeTestData[index], options, false, 0); } @@ -251,7 +251,7 @@ TEST(SymbolicConstantsMach, StringToException) { NUL_TEST_DATA("1\0002"), }; - for (size_t index = 0; index < ArraySize(kNULTestData); ++index) { + for (size_t index = 0; index < base::size(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); @@ -334,7 +334,7 @@ void TestExceptionMaskToString(exception_mask_t value, } TEST(SymbolicConstantsMach, ExceptionMaskToString) { - for (size_t index = 0; index < ArraySize(kExceptionMaskTestData); ++index) { + for (size_t index = 0; index < base::size(kExceptionMaskTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestExceptionMaskToString(kExceptionMaskTestData[index].exception_mask, kExceptionMaskTestData[index].full_name, @@ -389,11 +389,12 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { kAllowFullName | kAllowShortName | kAllowNumber | kAllowOr, }; - for (size_t option_index = 0; option_index < ArraySize(kOptions); + for (size_t option_index = 0; option_index < base::size(kOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kOptions[option_index]; - for (size_t index = 0; index < ArraySize(kExceptionMaskTestData); ++index) { + for (size_t index = 0; index < base::size(kExceptionMaskTestData); + ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); exception_mask_t exception_mask = kExceptionMaskTestData[index].exception_mask; @@ -444,7 +445,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { "", }; - for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { + for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionMask(kNegativeTestData[index], options, false, 0); } @@ -470,7 +471,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { NUL_TEST_DATA("ARITHMETIC|\0EMULATION"), }; - for (size_t index = 0; index < ArraySize(kNULTestData); ++index) { + for (size_t index = 0; index < base::size(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); @@ -505,7 +506,7 @@ TEST(SymbolicConstantsMach, StringToExceptionMask) { EXC_MASK_SYSCALL | 0x100}, }; - for (size_t index = 0; index < ArraySize(kNonCanonicalTestData); ++index) { + for (size_t index = 0; index < base::size(kNonCanonicalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionMask(kNonCanonicalTestData[index].string, kNonCanonicalTestData[index].options, @@ -576,7 +577,7 @@ void TestExceptionBehaviorToString(exception_behavior_t value, } TEST(SymbolicConstantsMach, ExceptionBehaviorToString) { - for (size_t index = 0; index < ArraySize(kExceptionBehaviorTestData); + for (size_t index = 0; index < base::size(kExceptionBehaviorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestExceptionBehaviorToString(kExceptionBehaviorTestData[index].behavior, @@ -606,11 +607,11 @@ void TestStringToExceptionBehavior(const base::StringPiece& string, } TEST(SymbolicConstantsMach, StringToExceptionBehavior) { - for (size_t option_index = 0; option_index < ArraySize(kNormalOptions); + for (size_t option_index = 0; option_index < base::size(kNormalOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kNormalOptions[option_index]; - for (size_t index = 0; index < ArraySize(kExceptionBehaviorTestData); + for (size_t index = 0; index < base::size(kExceptionBehaviorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); exception_behavior_t behavior = @@ -656,7 +657,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { "", }; - for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { + for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionBehavior( kNegativeTestData[index], options, false, 0); @@ -682,7 +683,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { NUL_TEST_DATA("STATE_IDENTITY|\0MACH"), }; - for (size_t index = 0; index < ArraySize(kNULTestData); ++index) { + for (size_t index = 0; index < base::size(kNULTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); base::StringPiece string(kNULTestData[index].string, kNULTestData[index].length); @@ -719,7 +720,7 @@ TEST(SymbolicConstantsMach, StringToExceptionBehavior) { implicit_cast<exception_behavior_t>(MACH_EXCEPTION_CODES | 0x2)}, }; - for (size_t index = 0; index < ArraySize(kNonCanonicalTestData); ++index) { + for (size_t index = 0; index < base::size(kNonCanonicalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToExceptionBehavior(kNonCanonicalTestData[index].string, kNonCanonicalTestData[index].options, @@ -836,7 +837,7 @@ void TestThreadStateFlavorToString(exception_type_t value, } TEST(SymbolicConstantsMach, ThreadStateFlavorToString) { - for (size_t index = 0; index < ArraySize(kThreadStateFlavorTestData); + for (size_t index = 0; index < base::size(kThreadStateFlavorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestThreadStateFlavorToString(kThreadStateFlavorTestData[index].flavor, @@ -878,11 +879,11 @@ void TestStringToThreadStateFlavor(const base::StringPiece& string, } TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { - for (size_t option_index = 0; option_index < ArraySize(kNormalOptions); + for (size_t option_index = 0; option_index < base::size(kNormalOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kNormalOptions[option_index]; - for (size_t index = 0; index < ArraySize(kThreadStateFlavorTestData); + for (size_t index = 0; index < base::size(kThreadStateFlavorTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); thread_state_flavor_t flavor = kThreadStateFlavorTestData[index].flavor; @@ -952,7 +953,7 @@ TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { #endif }; - for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { + for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToThreadStateFlavor( kNegativeTestData[index], options, false, 0); @@ -1018,7 +1019,7 @@ TEST(SymbolicConstantsMach, StringToThreadStateFlavor) { #endif }; - for (size_t index = 0; index < ArraySize(kNULTestData); ++index) { + for (size_t index = 0; index < base::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 d476edbc..93a63882 100644 --- a/util/misc/arraysize.h +++ b/util/misc/arraysize.h @@ -34,6 +34,10 @@ constexpr size_t ArraySizeHelper() noexcept { } // namespace crashpad //! \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. #define ArraySize(array) crashpad::internal::ArraySizeHelper<decltype(array)>() #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 d8abd377..16d81b72 100644 --- a/util/misc/capture_context_test_util_win.cc +++ b/util/misc/capture_context_test_util_win.cc @@ -15,8 +15,8 @@ #include "util/misc/capture_context_test_util.h" #include "util/win/context_wrappers.h" +#include "base/stl_util.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -59,7 +59,7 @@ void SanityCheckContext(const NativeCPUContext& context) { #if defined(ARCH_CPU_X86) // fxsave doesn’t write these bytes. - for (size_t i = 464; i < ArraySize(context.ExtendedRegisters); ++i) { + for (size_t i = 464; i < base::size(context.ExtendedRegisters); ++i) { SCOPED_TRACE(i); EXPECT_EQ(context.ExtendedRegisters[i], 0); } @@ -69,7 +69,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 < ArraySize(context.FltSave.Reserved4); ++i) { + for (size_t i = 0; i < base::size(context.FltSave.Reserved4); ++i) { SCOPED_TRACE(i); EXPECT_EQ(context.FltSave.Reserved4[i], 0); } @@ -81,7 +81,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 < ArraySize(context.VectorRegister); ++i) { + for (size_t i = 0; i < base::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 ca4bf009..6bfb87b4 100644 --- a/util/misc/clock_test.cc +++ b/util/misc/clock_test.cc @@ -20,9 +20,9 @@ #include "base/format_macros.h" #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -83,7 +83,7 @@ TEST(Clock, SleepNanoseconds) { static_cast<uint64_t>(5E7), // 50 milliseconds }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 aa5c786e..f05bdcf4 100644 --- a/util/misc/paths_win.cc +++ b/util/misc/paths_win.cc @@ -17,19 +17,21 @@ #include <windows.h> #include "base/logging.h" -#include "util/misc/arraysize.h" +#include "base/stl_util.h" namespace crashpad { // static bool Paths::Executable(base::FilePath* path) { wchar_t executable_path[_MAX_PATH]; - unsigned int len = GetModuleFileName( - nullptr, executable_path, static_cast<DWORD>(ArraySize(executable_path))); + unsigned int len = + GetModuleFileName(nullptr, + executable_path, + static_cast<DWORD>(base::size(executable_path))); if (len == 0) { PLOG(ERROR) << "GetModuleFileName"; return false; - } else if (len >= ArraySize(executable_path)) { + } else if (len >= base::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 5d9fad62..f5f0f325 100644 --- a/util/misc/random_string_test.cc +++ b/util/misc/random_string_test.cc @@ -18,8 +18,8 @@ #include <set> +#include "base/stl_util.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -33,7 +33,7 @@ TEST(RandomString, RandomString) { const std::string allowed_characters("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); size_t character_counts[26] = {}; - ASSERT_EQ(allowed_characters.size(), ArraySize(character_counts)); + ASSERT_EQ(allowed_characters.size(), base::size(character_counts)); std::set<std::string> 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 < ArraySize(character_counts); + character_index < base::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 b8519198..35f9ecd4 100644 --- a/util/misc/uuid_test.cc +++ b/util/misc/uuid_test.cc @@ -21,9 +21,9 @@ #include "base/format_macros.h" #include "base/scoped_generic.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -95,12 +95,12 @@ TEST(UUID, UUID) { ++uuid.data_3; EXPECT_NE(uuid, uuid_2); --uuid.data_3; - for (size_t index = 0; index < ArraySize(uuid.data_4); ++index) { + for (size_t index = 0; index < base::size(uuid.data_4); ++index) { ++uuid.data_4[index]; EXPECT_NE(uuid, uuid_2); --uuid.data_4[index]; } - for (size_t index = 0; index < ArraySize(uuid.data_5); ++index) { + for (size_t index = 0; index < base::size(uuid.data_5); ++index) { ++uuid.data_5[index]; EXPECT_NE(uuid, uuid_2); --uuid.data_5[index]; @@ -190,7 +190,7 @@ TEST(UUID, FromString) { uuid_zero.InitializeToZero(); const std::string empty_uuid = uuid_zero.ToString(); - for (size_t index = 0; index < ArraySize(kCases); ++index) { + for (size_t index = 0; index < base::size(kCases); ++index) { const TestCase& test_case = kCases[index]; SCOPED_TRACE(base::StringPrintf( "index %" PRIuS ": %s", index, test_case.uuid_string)); @@ -226,7 +226,7 @@ TEST(UUID, FromString) { }; // clang-format on EXPECT_TRUE(uuid.InitializeFromString( - base::StringPiece16(kChar16UUID, ArraySize(kChar16UUID)))); + base::StringPiece16(kChar16UUID, base::size(kChar16UUID)))); EXPECT_EQ(uuid.ToString(), "f32e5bdc-2681-4c73-a4e6-333ffd33b333"); #if defined(OS_WIN) diff --git a/util/net/http_transport_socket.cc b/util/net/http_transport_socket.cc index b390238f..f2dd6812 100644 --- a/util/net/http_transport_socket.cc +++ b/util/net/http_transport_socket.cc @@ -24,10 +24,10 @@ #include "base/numerics/safe_conversions.h" #include "base/posix/eintr_wrapper.h" #include "base/scoped_generic.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "util/file/file_io.h" -#include "util/misc/arraysize.h" #include "util/net/http_body.h" #include "util/net/url.h" #include "util/stdlib/string_number_conversion.h" @@ -366,7 +366,7 @@ bool WriteRequest(Stream* stream, FileOperationResult data_bytes; do { - constexpr size_t kCRLFSize = ArraySize(kCRLFTerminator) - 1; + constexpr size_t kCRLFSize = base::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 06d0b7b2..09876882 100644 --- a/util/net/http_transport_win.cc +++ b/util/net/http_transport_win.cc @@ -25,13 +25,13 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/scoped_generic.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "package.h" #include "util/file/file_io.h" -#include "util/misc/arraysize.h" #include "util/net/http_body.h" #include "util/numeric/safe_assignment.h" #include "util/win/module_version.h" @@ -96,7 +96,7 @@ std::string WinHttpMessage(const char* extra) { error_code, 0, msgbuf, - static_cast<DWORD>(ArraySize(msgbuf)), + static_cast<DWORD>(base::size(msgbuf)), NULL); 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 f5dc8adc..08bc551c 100644 --- a/util/numeric/checked_address_range_test.cc +++ b/util/numeric/checked_address_range_test.cc @@ -19,10 +19,10 @@ #include <limits> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -119,7 +119,7 @@ TEST(CheckedAddressRange, IsValid) { {0xffffffffffffffff, 1, kInvalid}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 2977b42e..9d611e8d 100644 --- a/util/numeric/checked_range_test.cc +++ b/util/numeric/checked_range_test.cc @@ -20,9 +20,9 @@ #include <limits> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -78,7 +78,7 @@ TEST(CheckedRange, IsValid) { {0xffffffff, 0xffffffff, false}, }; - for (size_t index = 0; index < ArraySize(kUnsignedTestData); ++index) { + for (size_t index = 0; index < base::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 < ArraySize(kSignedTestData); ++index) { + for (size_t index = 0; index < base::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<uint32_t> parent_range(0x2000, 0x1000); ASSERT_TRUE(parent_range.IsValid()); - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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<uint32_t> parent_range(0x2000, 0x1000); ASSERT_TRUE(parent_range.IsValid()); - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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<uint32_t> first_range(0x2000, 0x1000); ASSERT_TRUE(first_range.IsValid()); - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 22f89f52..238f158c 100644 --- a/util/posix/close_multiple.cc +++ b/util/posix/close_multiple.cc @@ -25,10 +25,10 @@ #include "base/files/scoped_file.h" #include "base/logging.h" #include "base/posix/eintr_wrapper.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "build/build_config.h" #include "util/file/directory_reader.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #if defined(OS_MACOSX) @@ -153,7 +153,7 @@ void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { int maxfilesperproc; size_t maxfilesperproc_size = sizeof(maxfilesperproc); if (sysctl(oid, - ArraySize(oid), + base::size(oid), &maxfilesperproc, &maxfilesperproc_size, nullptr, diff --git a/util/posix/process_info_mac.cc b/util/posix/process_info_mac.cc index 8b9a6ec0..9e86e084 100644 --- a/util/posix/process_info_mac.cc +++ b/util/posix/process_info_mac.cc @@ -18,7 +18,7 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" -#include "util/misc/arraysize.h" +#include "base/stl_util.h" namespace crashpad { @@ -33,7 +33,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, ArraySize(mib), &kern_proc_info_, &len, nullptr, 0) != 0) { + if (sysctl(mib, base::size(mib), &kern_proc_info_, &len, nullptr, 0) != 0) { PLOG(ERROR) << "sysctl for pid " << pid; return false; } @@ -112,7 +112,7 @@ std::set<gid_t> ProcessInfo::SupplementaryGroups() const { const short ngroups = kern_proc_info_.kp_eproc.e_ucred.cr_ngroups; DCHECK_GE(ngroups, 0); DCHECK_LE(static_cast<size_t>(ngroups), - ArraySize(kern_proc_info_.kp_eproc.e_ucred.cr_groups)); + base::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<gid_t>(&groups[0], &groups[ngroups]); @@ -169,7 +169,7 @@ bool ProcessInfo::Arguments(std::vector<std::string>* argv) const { do { int mib[] = {CTL_KERN, KERN_PROCARGS2, pid}; int rv = - sysctl(mib, ArraySize(mib), nullptr, &args_size_estimate, nullptr, 0); + sysctl(mib, base::size(mib), nullptr, &args_size_estimate, nullptr, 0); if (rv != 0) { PLOG(ERROR) << "sysctl (size) for pid " << pid; return false; @@ -177,7 +177,7 @@ bool ProcessInfo::Arguments(std::vector<std::string>* argv) const { args_size = args_size_estimate + 1; args.resize(args_size); - rv = sysctl(mib, ArraySize(mib), &args[0], &args_size, nullptr, 0); + rv = sysctl(mib, base::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 0a6a1fa1..5c69e7e4 100644 --- a/util/posix/scoped_mmap_test.cc +++ b/util/posix/scoped_mmap_test.cc @@ -20,10 +20,10 @@ #include "base/numerics/safe_conversions.h" #include "base/rand_util.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "test/gtest_death.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -151,7 +151,7 @@ TEST(ScopedMmapDeathTest, ResetAddrLen_Shrink) { EXPECT_EQ(mapping.len(), 3 * kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < ArraySize(cookies); ++index) { + for (size_t index = 0; index < base::size(cookies); ++index) { cookies[index].SetUp(reinterpret_cast<uint64_t*>( mapping.addr_as<uintptr_t>() + index * kPageSize)); } @@ -186,7 +186,7 @@ TEST(ScopedMmap, ResetAddrLen_Grow) { EXPECT_EQ(mapping.len(), kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < ArraySize(cookies); ++index) { + for (size_t index = 0; index < base::size(cookies); ++index) { cookies[index].SetUp(reinterpret_cast<uint64_t*>( reinterpret_cast<uintptr_t>(pages) + index * kPageSize)); } @@ -197,7 +197,7 @@ TEST(ScopedMmap, ResetAddrLen_Grow) { EXPECT_EQ(mapping.addr(), pages); EXPECT_EQ(mapping.len(), 3 * kPageSize); - for (size_t index = 0; index < ArraySize(cookies); ++index) { + for (size_t index = 0; index < base::size(cookies); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); EXPECT_EQ(cookies[index].Observed(), cookies[index].Expected()); } @@ -218,7 +218,7 @@ TEST(ScopedMmapDeathTest, ResetAddrLen_MoveDownAndGrow) { EXPECT_EQ(mapping.len(), kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < ArraySize(cookies); ++index) { + for (size_t index = 0; index < base::size(cookies); ++index) { cookies[index].SetUp(reinterpret_cast<uint64_t*>( reinterpret_cast<uintptr_t>(pages) + index * kPageSize)); } @@ -249,7 +249,7 @@ TEST(ScopedMmapDeathTest, ResetAddrLen_MoveUpAndShrink) { EXPECT_EQ(mapping.len(), 2 * kPageSize); TestCookie cookies[3]; - for (size_t index = 0; index < ArraySize(cookies); ++index) { + for (size_t index = 0; index < base::size(cookies); ++index) { cookies[index].SetUp(reinterpret_cast<uint64_t*>( reinterpret_cast<uintptr_t>(pages) + index * kPageSize)); } diff --git a/util/posix/signals.cc b/util/posix/signals.cc index 69cdfca3..1384de1e 100644 --- a/util/posix/signals.cc +++ b/util/posix/signals.cc @@ -19,7 +19,7 @@ #include <vector> #include "base/logging.h" -#include "util/misc/arraysize.h" +#include "base/stl_util.h" namespace crashpad { @@ -119,7 +119,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, ArraySize(actions_)); + DCHECK_LT(slot, base::size(actions_)); return &actions_[slot]; } @@ -153,7 +153,8 @@ bool Signals::InstallCrashHandlers(Handler handler, int flags, OldActions* old_actions) { return InstallHandlers( - std::vector<int>(kCrashSignals, kCrashSignals + ArraySize(kCrashSignals)), + std::vector<int>(kCrashSignals, + kCrashSignals + base::size(kCrashSignals)), handler, flags, old_actions); @@ -165,7 +166,7 @@ bool Signals::InstallTerminateHandlers(Handler handler, OldActions* old_actions) { return InstallHandlers( std::vector<int>(kTerminateSignals, - kTerminateSignals + ArraySize(kTerminateSignals)), + kTerminateSignals + base::size(kTerminateSignals)), handler, flags, old_actions); @@ -280,12 +281,12 @@ void Signals::RestoreHandlerAndReraiseSignalOnReturn( // static bool Signals::IsCrashSignal(int sig) { - return IsSignalInSet(sig, kCrashSignals, ArraySize(kCrashSignals)); + return IsSignalInSet(sig, kCrashSignals, base::size(kCrashSignals)); } // static bool Signals::IsTerminateSignal(int sig) { - return IsSignalInSet(sig, kTerminateSignals, ArraySize(kTerminateSignals)); + return IsSignalInSet(sig, kTerminateSignals, base::size(kTerminateSignals)); } } // namespace crashpad diff --git a/util/posix/signals_test.cc b/util/posix/signals_test.cc index b0c84071..d91e3cc6 100644 --- a/util/posix/signals_test.cc +++ b/util/posix/signals_test.cc @@ -26,13 +26,13 @@ #include "base/compiler_specific.h" #include "base/files/scoped_file.h" #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" #include "test/multiprocess.h" #include "test/scoped_temp_dir.h" -#include "util/misc/arraysize.h" #include "util/posix/scoped_mmap.h" namespace crashpad { @@ -341,7 +341,7 @@ TEST(Signals, WillSignalReraiseAutonomously) { {SIGHUP, SEGV_MAPERR, false}, {SIGINT, SI_USER, false}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::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 f1fa87f0..5937c576 100644 --- a/util/posix/symbolic_constants_posix.cc +++ b/util/posix/symbolic_constants_posix.cc @@ -18,9 +18,9 @@ #include <string.h> #include <sys/types.h> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" -#include "util/misc/arraysize.h" #include "util/misc/implicit_cast.h" #include "util/stdlib/string_number_conversion.h" @@ -137,9 +137,9 @@ constexpr const char* kSignalNames[] = { }; #if defined(OS_LINUX) || defined(OS_ANDROID) // NSIG is 64 to account for real-time signals. -static_assert(ArraySize(kSignalNames) == 32, "kSignalNames length"); +static_assert(base::size(kSignalNames) == 32, "kSignalNames length"); #else -static_assert(ArraySize(kSignalNames) == NSIG, "kSignalNames length"); +static_assert(base::size(kSignalNames) == NSIG, "kSignalNames length"); #endif constexpr char kSigPrefix[] = "SIG"; @@ -151,7 +151,7 @@ namespace crashpad { std::string SignalToString(int signal, SymbolicConstantToStringOptions options) { const char* signal_name = - implicit_cast<size_t>(signal) < ArraySize(kSignalNames) + implicit_cast<size_t>(signal) < base::size(kSignalNames) ? kSignalNames[signal] : nullptr; if (!signal_name) { @@ -176,7 +176,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<int>(ArraySize(kSignalNames)); + for (int index = 0; index < implicit_cast<int>(base::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 1a6e0b90..c7d62ee5 100644 --- a/util/posix/symbolic_constants_posix_test.cc +++ b/util/posix/symbolic_constants_posix_test.cc @@ -17,14 +17,14 @@ #include <signal.h> #include <sys/types.h> +#include "base/stl_util.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" #define NUL_TEST_DATA(string) \ - { string, ArraySize(string) - 1 } + { string, base::size(string) - 1 } namespace crashpad { namespace test { @@ -116,7 +116,7 @@ void TestSignalToString(int value, } TEST(SymbolicConstantsPOSIX, SignalToString) { - for (size_t index = 0; index < ArraySize(kSignalTestData); ++index) { + for (size_t index = 0; index < base::size(kSignalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestSignalToString(kSignalTestData[index].signal, kSignalTestData[index].full_name, @@ -171,11 +171,11 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { kAllowFullName | kAllowShortName | kAllowNumber, }; - for (size_t option_index = 0; option_index < ArraySize(kOptions); + for (size_t option_index = 0; option_index < base::size(kOptions); ++option_index) { SCOPED_TRACE(base::StringPrintf("option_index %zu", option_index)); StringToSymbolicConstantOptions options = kOptions[option_index]; - for (size_t index = 0; index < ArraySize(kSignalTestData); ++index) { + for (size_t index = 0; index < base::size(kSignalTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); int signal = kSignalTestData[index].signal; { @@ -213,7 +213,7 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { "", }; - for (size_t index = 0; index < ArraySize(kNegativeTestData); ++index) { + for (size_t index = 0; index < base::size(kNegativeTestData); ++index) { SCOPED_TRACE(base::StringPrintf("index %zu", index)); TestStringToSignal(kNegativeTestData[index], options, false, 0); } @@ -234,7 +234,7 @@ TEST(SymbolicConstantsPOSIX, StringToSignal) { NUL_TEST_DATA("1\0002"), }; - for (size_t index = 0; index < ArraySize(kNULTestData); ++index) { + for (size_t index = 0; index < base::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 9431d442..2df2b5cb 100644 --- a/util/process/process_memory_range_test.cc +++ b/util/process/process_memory_range_test.cc @@ -17,10 +17,10 @@ #include <limits> #include "base/logging.h" +#include "base/stl_util.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "test/process_type.h" -#include "util/misc/arraysize.h" #include "util/misc/from_pointer_cast.h" #include "util/process/process_memory_native.h" @@ -59,28 +59,28 @@ TEST(ProcessMemoryRange, Basic) { auto string1_addr = FromPointerCast<VMAddress>(kTestObject.string1); auto string2_addr = FromPointerCast<VMAddress>(kTestObject.string2); ASSERT_TRUE(range.ReadCStringSizeLimited( - string1_addr, ArraySize(kTestObject.string1), &string)); + string1_addr, base::size(kTestObject.string1), &string)); EXPECT_STREQ(string.c_str(), kTestObject.string1); ASSERT_TRUE(range.ReadCStringSizeLimited( - string2_addr, ArraySize(kTestObject.string2), &string)); + string2_addr, base::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, ArraySize(kTestObject.string1))); + range2.RestrictRange(string1_addr, base::size(kTestObject.string1))); EXPECT_TRUE(range2.ReadCStringSizeLimited( - string1_addr, ArraySize(kTestObject.string1), &string)); + string1_addr, base::size(kTestObject.string1), &string)); EXPECT_FALSE(range2.ReadCStringSizeLimited( - string2_addr, ArraySize(kTestObject.string2), &string)); + string2_addr, base::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, ArraySize(kTestObject.string1), &string)); + string1_addr, base::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 ee19429d..689b4ad5 100644 --- a/util/stdlib/string_number_conversion_test.cc +++ b/util/stdlib/string_number_conversion_test.cc @@ -18,8 +18,8 @@ #include <limits> +#include "base/stl_util.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -94,7 +94,7 @@ TEST(StringNumberConversion, StringToInt) { {"18446744073709551616", false, 0}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::size(kTestData); ++index) { int value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { @@ -114,7 +114,7 @@ TEST(StringNumberConversion, StringToInt) { // is split to avoid MSVC warning: // "decimal digit terminates octal escape sequence". static constexpr char input[] = "6\000" "6"; - std::string input_string(input, ArraySize(input) - 1); + std::string input_string(input, base::size(input) - 1); int output; EXPECT_FALSE(StringToNumber(input_string, &output)); } @@ -188,7 +188,7 @@ TEST(StringNumberConversion, StringToUnsignedInt) { {"18446744073709551616", false, 0}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::size(kTestData); ++index) { unsigned int value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { @@ -208,7 +208,7 @@ TEST(StringNumberConversion, StringToUnsignedInt) { // is split to avoid MSVC warning: // "decimal digit terminates octal escape sequence". static constexpr char input[] = "6\000" "6"; - std::string input_string(input, ArraySize(input) - 1); + std::string input_string(input, base::size(input) - 1); unsigned int output; EXPECT_FALSE(StringToNumber(input_string, &output)); } @@ -245,7 +245,7 @@ TEST(StringNumberConversion, StringToInt64) { {"0x7Fffffffffffffff", true, std::numeric_limits<int64_t>::max()}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::size(kTestData); ++index) { int64_t value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { @@ -295,7 +295,7 @@ TEST(StringNumberConversion, StringToUnsignedInt64) { {"0xFfffffffffffffff", true, std::numeric_limits<uint64_t>::max()}, }; - for (size_t index = 0; index < ArraySize(kTestData); ++index) { + for (size_t index = 0; index < base::size(kTestData); ++index) { uint64_t value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { diff --git a/util/stdlib/strlcpy_test.cc b/util/stdlib/strlcpy_test.cc index 172a09ab..bfb00fe2 100644 --- a/util/stdlib/strlcpy_test.cc +++ b/util/stdlib/strlcpy_test.cc @@ -20,10 +20,10 @@ #include <algorithm> #include "base/format_macros.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" namespace crashpad { namespace test { @@ -64,7 +64,7 @@ TEST(strlcpy, c16lcpy) { static constexpr base::char16 test_characters[] = {0x4d, 0xe9, 0x100, 0x151, 0x1e18}; - for (size_t index = 0; index < ArraySize(test_characters); ++index) { + for (size_t index = 0; index < base::size(test_characters); ++index) { base::char16 test_character = test_characters[index]; SCOPED_TRACE(base::StringPrintf( "character index %" PRIuS ", character 0x%x", index, test_character)); @@ -78,13 +78,13 @@ TEST(strlcpy, c16lcpy) { EXPECT_EQ(c16lcpy(destination.data, test_string.c_str(), - ArraySize(destination.data)), + base::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, ArraySize(destination.data) - 1); + std::min(length, base::size(destination.data) - 1); EXPECT_EQ(destination.data[expected_destination_length], '\0'); EXPECT_EQ(C16Len(destination.data), expected_destination_length); @@ -97,15 +97,15 @@ TEST(strlcpy, c16lcpy) { // of the buffer passed to c16lcpy. EXPECT_TRUE(C16Memcmp(expected_untouched.lead_guard, destination.lead_guard, - ArraySize(destination.lead_guard)) == 0); + base::size(destination.lead_guard)) == 0); size_t expected_untouched_length = - ArraySize(destination.data) - expected_destination_length - 1; + base::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, - ArraySize(destination.trail_guard)) == 0); + base::size(destination.trail_guard)) == 0); } } } diff --git a/util/stdlib/thread_safe_vector_test.cc b/util/stdlib/thread_safe_vector_test.cc index 183c6366..1d26b09d 100644 --- a/util/stdlib/thread_safe_vector_test.cc +++ b/util/stdlib/thread_safe_vector_test.cc @@ -14,8 +14,8 @@ #include "util/stdlib/thread_safe_vector.h" +#include "base/stl_util.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" #include "util/thread/thread.h" namespace crashpad { @@ -54,12 +54,12 @@ TEST(ThreadSafeVector, ThreadSafeVector) { EXPECT_TRUE(vector.empty()); ThreadSafeVectorTestThread threads[100]; - for (size_t index = 0; index < ArraySize(threads); ++index) { + for (size_t index = 0; index < base::size(threads); ++index) { threads[index].SetTestParameters( &thread_safe_vector, static_cast<int>(index * kElementsPerThread)); } - for (size_t index = 0; index < ArraySize(threads); ++index) { + for (size_t index = 0; index < base::size(threads); ++index) { threads[index].Start(); if (index % 10 == 0) { @@ -76,8 +76,8 @@ TEST(ThreadSafeVector, ThreadSafeVector) { std::vector<int> drained = thread_safe_vector.Drain(); vector.insert(vector.end(), drained.begin(), drained.end()); - bool found[ArraySize(threads) * kElementsPerThread] = {}; - EXPECT_EQ(vector.size(), ArraySize(found)); + bool found[base::size(threads) * kElementsPerThread] = {}; + EXPECT_EQ(vector.size(), base::size(found)); for (int element : vector) { EXPECT_FALSE(found[element]) << element; found[element] = true; diff --git a/util/synchronization/semaphore_test.cc b/util/synchronization/semaphore_test.cc index fedead13..4f1c1cd5 100644 --- a/util/synchronization/semaphore_test.cc +++ b/util/synchronization/semaphore_test.cc @@ -16,8 +16,8 @@ #include <sys/types.h> +#include "base/stl_util.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" #if defined(OS_POSIX) #include <pthread.h> @@ -126,7 +126,7 @@ TEST(Semaphore, TenThreaded) { Semaphore semaphore(5); ThreadMainInfo info[10]; size_t iterations = 0; - for (size_t index = 0; index < ArraySize(info); ++index) { + for (size_t index = 0; index < base::size(info); ++index) { info[index].semaphore = &semaphore; info[index].iterations = index; iterations += info[index].iterations; @@ -138,7 +138,7 @@ TEST(Semaphore, TenThreaded) { semaphore.Signal(); } - for (size_t index = 0; index < ArraySize(info); ++index) { + for (size_t index = 0; index < base::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 f186ed20..94920e7f 100644 --- a/util/thread/thread_log_messages_test.cc +++ b/util/thread/thread_log_messages_test.cc @@ -18,9 +18,9 @@ #include <sys/types.h> #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "gtest/gtest.h" -#include "util/misc/arraysize.h" #include "util/thread/thread.h" namespace crashpad { @@ -94,8 +94,8 @@ TEST(ThreadLogMessages, Basic) { const std::vector<std::string>& log_messages = thread_log_messages.log_messages(); - EXPECT_EQ(log_messages.size(), ArraySize(kMessages)); - for (size_t index = 0; index < ArraySize(kMessages); ++index) { + EXPECT_EQ(log_messages.size(), base::size(kMessages)); + for (size_t index = 0; index < base::size(kMessages); ++index) { EXPECT_EQ(MessageString(log_messages[index]), kMessages[index]) << "index " << index; } @@ -174,7 +174,7 @@ TEST(ThreadLogMessages, Multithreaded) { LoggingTestThread threads[20]; int start = 0; - for (size_t index = 0; index < ArraySize(threads); ++index) { + for (size_t index = 0; index < base::size(threads); ++index) { threads[index].Initialize( index, static_cast<int>(start), static_cast<int>(index)); start += static_cast<int>(index); diff --git a/util/win/command_line_test.cc b/util/win/command_line_test.cc index e5ceef87..032d5555 100644 --- a/util/win/command_line_test.cc +++ b/util/win/command_line_test.cc @@ -20,9 +20,9 @@ #include "base/logging.h" #include "base/scoped_generic.h" +#include "base/stl_util.h" #include "gtest/gtest.h" #include "test/errors.h" -#include "util/misc/arraysize.h" #include "util/win/scoped_local_alloc.h" namespace crashpad { @@ -65,7 +65,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"argument 1", L"argument 2", }; - AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); + AppendCommandLineArgumentTest(base::size(kArguments), kArguments); } { @@ -77,7 +77,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"argument 2", L"\\some\\path with\\spaces", }; - AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); + AppendCommandLineArgumentTest(base::size(kArguments), kArguments); } { @@ -89,7 +89,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"she said, \"you had me at hello\"", L"\\some\\path with\\spaces", }; - AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); + AppendCommandLineArgumentTest(base::size(kArguments), kArguments); } { @@ -102,7 +102,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"argument3", L"argument4", }; - AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); + AppendCommandLineArgumentTest(base::size(kArguments), kArguments); } { @@ -113,7 +113,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"\\some\\directory with\\spaces\\", L"argument2", }; - AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); + AppendCommandLineArgumentTest(base::size(kArguments), kArguments); } { @@ -124,7 +124,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"", L"argument2", }; - AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); + AppendCommandLineArgumentTest(base::size(kArguments), kArguments); } { @@ -159,7 +159,7 @@ TEST(CommandLine, AppendCommandLineArgument) { L"\"\"", L" \t\n\v\"", }; - AppendCommandLineArgumentTest(ArraySize(kArguments), kArguments); + AppendCommandLineArgumentTest(base::size(kArguments), kArguments); } } diff --git a/util/win/exception_handler_server.cc b/util/win/exception_handler_server.cc index 8ca3d259..2593ff2d 100644 --- a/util/win/exception_handler_server.cc +++ b/util/win/exception_handler_server.cc @@ -23,13 +23,13 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" #include "base/rand_util.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "minidump/minidump_file_writer.h" #include "snapshot/crashpad_info_client_options.h" #include "snapshot/win/process_snapshot_win.h" #include "util/file/file_writer.h" -#include "util/misc/arraysize.h" #include "util/misc/tri_state.h" #include "util/misc/uuid.h" #include "util/win/get_function.h" @@ -308,7 +308,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 < ArraySize(thread_handles); ++i) { + for (size_t i = 0; i < base::size(thread_handles); ++i) { HANDLE pipe; if (first_pipe_instance_.is_valid()) { pipe = first_pipe_instance_.release(); @@ -360,7 +360,7 @@ void ExceptionHandlerServer::Run(Delegate* delegate) { } // Signal to the named pipe instances that they should terminate. - for (size_t i = 0; i < ArraySize(thread_handles); ++i) { + for (size_t i = 0; i < base::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 118bfef7..e9a9b61a 100644 --- a/util/win/ntstatus_logging.cc +++ b/util/win/ntstatus_logging.cc @@ -16,8 +16,8 @@ #include <string> +#include "base/stl_util.h" #include "base/strings/stringprintf.h" -#include "util/misc/arraysize.h" namespace { @@ -30,7 +30,7 @@ std::string FormatNtstatus(DWORD ntstatus) { ntstatus, 0, msgbuf, - static_cast<DWORD>(ArraySize(msgbuf)), + static_cast<DWORD>(base::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 412f8da0..359e3308 100644 --- a/util/win/registration_protocol_win.cc +++ b/util/win/registration_protocol_win.cc @@ -18,7 +18,7 @@ #include <windows.h> #include "base/logging.h" -#include "util/misc/arraysize.h" +#include "base/stl_util.h" #include "util/win/exception_handler_server.h" #include "util/win/scoped_handle.h" @@ -168,7 +168,8 @@ const void* GetSecurityDescriptorForNamedPipeInstance(size_t* size) { ACL_REVISION, // AclRevision. 0, // Sbz1. sizeof(kSecDescBlob.sacl), // AclSize. - static_cast<WORD>(ArraySize(kSecDescBlob.sacl.ace)), // AceCount. + static_cast<WORD>( + base::size(kSecDescBlob.sacl.ace)), // AceCount. 0, // Sbz2. }, @@ -189,8 +190,8 @@ const void* GetSecurityDescriptorForNamedPipeInstance(size_t* size) { { SID_REVISION, // Revision. // SubAuthorityCount. - static_cast<BYTE>( - ArraySize(kSecDescBlob.sacl.ace[0].sid.SubAuthority)), + static_cast<BYTE>(base::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 a62fb143..d2e4b6dd 100644 --- a/util/win/safe_terminate_process_test.cc +++ b/util/win/safe_terminate_process_test.cc @@ -22,12 +22,12 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/macros.h" +#include "base/stl_util.h" #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" -#include "util/misc/arraysize.h" #include "util/win/scoped_handle.h" namespace crashpad { @@ -149,7 +149,7 @@ TEST(SafeTerminateProcess, PatchBadly) { }; void* target = reinterpret_cast<void*>(TerminateProcess); - ScopedExecutablePatch executable_patch(target, patch, ArraySize(patch)); + ScopedExecutablePatch executable_patch(target, patch, base::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 b3eeffaa18c22288c739325a3a8293065e13593e Mon Sep 17 00:00:00 2001 From: Reid Kleckner <rnk@google.com> Date: Fri, 4 Jan 2019 11:39:41 -0800 Subject: [PATCH 115/401] Use << instead of , to log "NtQueryInformationProcess" Fixes a -Wunused-value warning found by the latest version of clang. R=mark@chromium.org Bug: 917419 Change-Id: I6178c1534adc7e25e5b75f6a6ab90497a86de23f Reviewed-on: https://chromium-review.googlesource.com/c/1395945 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Reid Kleckner <rnk@chromium.org> --- util/win/process_info.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/win/process_info.cc b/util/win/process_info.cc index cd6bcd3e..ff8f34db 100644 --- a/util/win/process_info.cc +++ b/util/win/process_info.cc @@ -224,7 +224,7 @@ bool GetProcessBasicInformation(HANDLE process, sizeof(wow64_peb_address), &bytes_returned); if (!NT_SUCCESS(status)) { - NTSTATUS_LOG(ERROR, status), "NtQueryInformationProcess"; + NTSTATUS_LOG(ERROR, status) << "NtQueryInformationProcess"; return false; } if (bytes_returned != sizeof(wow64_peb_address)) { From 670dec4b612e6af4fd8a72b6928a34f049e776c2 Mon Sep 17 00:00:00 2001 From: Dave Moore <davemoore@google.com> Date: Thu, 3 Jan 2019 16:26:45 -0800 Subject: [PATCH 116/401] [syscalls] Change references to ZX_VM_FLAG_* to ZX_VM_* Test: Existing Change-Id: I36fde186de372d2b86807f4da4e6e589a1b19706 Reviewed-on: https://chromium-review.googlesource.com/c/1395479 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- snapshot/fuchsia/process_reader_fuchsia.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapshot/fuchsia/process_reader_fuchsia.cc b/snapshot/fuchsia/process_reader_fuchsia.cc index e60766af..0c8b6ca7 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.cc +++ b/snapshot/fuchsia/process_reader_fuchsia.cc @@ -56,7 +56,7 @@ void GetStackRegions( LOG(ERROR) << "stack range has unexpected type, continuing anyway"; } - if (range_with_sp.u.mapping.mmu_flags & ZX_VM_FLAG_PERM_EXECUTE) { + if (range_with_sp.u.mapping.mmu_flags & ZX_VM_PERM_EXECUTE) { LOG(ERROR) << "stack range is unexpectedly marked executable, continuing anyway"; } From fb667c9892e7e5e9377e1804ebe2463454eddbab Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 7 Jan 2019 15:31:19 -0800 Subject: [PATCH 117/401] linux: Handle negative offsets in MemoryMap offsets in the MemoryMap are expressed as two's complement while Crashpad's and mini_chromium's string conversion functions expect negative numbers to be expressed with a '-' character. Convert the string as unsigned and then re-interpret to signed when necessary. Bug: 914246 Change-Id: I76aaf092ea7ad98806be7a3f380dab4ca0425ed6 Reviewed-on: https://chromium-review.googlesource.com/c/1399372 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/linux/memory_map.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index 0bcca3fa..02bc3669 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -40,16 +40,18 @@ bool LocalStringToNumber(const std::string& string, Type* number) { static_assert(sizeof(Type) == sizeof(int) || sizeof(Type) == sizeof(int64_t), "Unexpected Type size"); + char data[sizeof(Type)]; if (sizeof(Type) == sizeof(int)) { - return std::numeric_limits<Type>::is_signed - ? StringToNumber(string, reinterpret_cast<int*>(number)) - : StringToNumber(string, - reinterpret_cast<unsigned int*>(number)); + if (!StringToNumber(string, reinterpret_cast<unsigned int*>(data))) { + return false; + } } else { - return std::numeric_limits<Type>::is_signed - ? StringToNumber(string, reinterpret_cast<int64_t*>(number)) - : StringToNumber(string, reinterpret_cast<uint64_t*>(number)); + if (!StringToNumber(string, reinterpret_cast<uint64_t*>(data))) { + return false; + } } + *number = *reinterpret_cast<Type*>(data); + return true; } template <typename Type> From ec676b3f67ac1d96459cf72fbe7f7b0cd4033016 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 8 Jan 2019 09:00:55 -0800 Subject: [PATCH 118/401] linux: Use bit_cast to convert types Change-Id: Ie7a5be80169850bbfa188b1f141f97d79683f9a5 Reviewed-on: https://chromium-review.googlesource.com/c/1401103 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/linux/memory_map.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index 02bc3669..4f02ce88 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -18,6 +18,7 @@ #include <string.h> #include <sys/sysmacros.h> +#include "base/bit_cast.h" #include "base/files/file_path.h" #include "base/logging.h" #include "build/build_config.h" @@ -50,7 +51,7 @@ bool LocalStringToNumber(const std::string& string, Type* number) { return false; } } - *number = *reinterpret_cast<Type*>(data); + *number = bit_cast<Type>(data); return true; } From e7895b44048166dd02824ddbb757e99eebe150bf Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Mon, 7 Jan 2019 09:38:47 -0800 Subject: [PATCH 119/401] Include changes from chromium These changes were made in the upstream version of crashpad without being contributed back to crashpad. Bug: crashpad:271 Change-Id: I60f6dfd206191e65bac41978a7c88d06b8c3cee9 Reviewed-on: https://chromium-review.googlesource.com/c/1389238 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- handler/BUILD.gn | 9 +++++++-- snapshot/mac/mach_o_image_annotations_reader_test.cc | 8 +++++++- snapshot/win/exception_snapshot_win_test.cc | 8 +++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/handler/BUILD.gn b/handler/BUILD.gn index ea33260c..7a91b1c3 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -145,10 +145,15 @@ crashpad_executable("crashpad_handler") { "@loader_path/../../../../../../../..", # The handler is also in - # Content Shell.app/Contents/Frameworks/Content Shell Framework.framework/Helpers/ + # Content Shell.app/Contents/Frameworks/Content Shell Framework.framework/Versions/C/Helpers/ # so set the rpath for that too. "-rpath", - "@loader_path/../../../../..", + "@loader_path/../../../../../../..", + + # The handler can also be executed in an unbundled framework at + # Chromium Framework.framework/Versions/A/Helpers/ + "-rpath", + "@loader_path/../../../..", ] } } diff --git a/snapshot/mac/mach_o_image_annotations_reader_test.cc b/snapshot/mac/mach_o_image_annotations_reader_test.cc index 69302503..8659a141 100644 --- a/snapshot/mac/mach_o_image_annotations_reader_test.cc +++ b/snapshot/mac/mach_o_image_annotations_reader_test.cc @@ -461,7 +461,13 @@ TEST(MachOImageAnnotationsReader, CrashAbort) { test_mach_o_image_annotations_reader.Run(); } -TEST(MachOImageAnnotationsReader, CrashModuleInitialization) { +#if defined(ADDRESS_SANITIZER) +// https://crbug.com/844396 +#define MAYBE_CrashModuleInitialization DISABLED_CrashModuleInitialization +#else +#define MAYBE_CrashModuleInitialization CrashModuleInitialization +#endif +TEST(MachOImageAnnotationsReader, MAYBE_CrashModuleInitialization) { TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader( TestMachOImageAnnotationsReader::kCrashModuleInitialization); test_mach_o_image_annotations_reader.Run(); diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index 537b4ca8..486e6df3 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -280,7 +280,13 @@ void TestDumpWithoutCrashingChild(TestPaths::Architecture architecture) { EXPECT_EQ(child.WaitForExit(), 0u); } -TEST(SimulateCrash, ChildDumpWithoutCrashing) { +#if defined(ADDRESS_SANITIZER) +// https://crbug.com/845011 +#define MAYBE_ChildDumpWithoutCrashing DISABLED_ChildDumpWithoutCrashing +#else +#define MAYBE_ChildDumpWithoutCrashing ChildDumpWithoutCrashing +#endif +TEST(SimulateCrash, MAYBE_ChildDumpWithoutCrashing) { TestDumpWithoutCrashingChild(TestPaths::Architecture::kDefault); } From 732768cc9df10b1a526d42cc621fad52c18515e8 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 10 Jan 2019 10:25:28 -0800 Subject: [PATCH 120/401] Upstream change from chromium This was part of a change to delete base::ThreadLocalStorage::StaticSlot. Bug: crashpad:271 Change-Id: I0df76318aef05cbaecab660253cb388e3929f693 Reviewed-on: https://chromium-review.googlesource.com/c/1405788 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- util/thread/thread_log_messages.cc | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/util/thread/thread_log_messages.cc b/util/thread/thread_log_messages.cc index 60be08b5..60c82483 100644 --- a/util/thread/thread_log_messages.cc +++ b/util/thread/thread_log_messages.cc @@ -46,10 +46,6 @@ class ThreadLogMessagesMaster { private: ThreadLogMessagesMaster() { - DCHECK(!tls_.initialized()); - tls_.Initialize(nullptr); - DCHECK(tls_.initialized()); - DCHECK(!logging::GetLogMessageHandler()); logging::SetLogMessageHandler(LogMessageHandler); } @@ -62,7 +58,7 @@ class ThreadLogMessagesMaster { size_t message_start, const std::string& string) { std::vector<std::string>* log_messages = - reinterpret_cast<std::vector<std::string>*>(tls_.Get()); + reinterpret_cast<std::vector<std::string>*>(GetInstance()->tls_.Get()); if (log_messages) { log_messages->push_back(string); } @@ -72,15 +68,11 @@ class ThreadLogMessagesMaster { return false; } - static base::ThreadLocalStorage::StaticSlot tls_; + base::ThreadLocalStorage::Slot tls_; DISALLOW_COPY_AND_ASSIGN(ThreadLogMessagesMaster); }; -// static -base::ThreadLocalStorage::StaticSlot ThreadLogMessagesMaster::tls_ - = TLS_INITIALIZER; - } // namespace ThreadLogMessages::ThreadLogMessages() : log_messages_() { From dc6dee855ec9f574abc66c42b6993a8d427db8e9 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 10 Jan 2019 14:02:54 -0800 Subject: [PATCH 121/401] android: use size_t to align A uint8_t won't be bit-extended, zero-ing all the upper bits of value. Change-Id: Iae41eeb4a014de5ed47ad599081959250a7bbe9c Reviewed-on: https://chromium-review.googlesource.com/c/1405691 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- compat/android/sys/mman.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compat/android/sys/mman.cc b/compat/android/sys/mman.cc index 4c29a9df..d890d84d 100644 --- a/compat/android/sys/mman.cc +++ b/compat/android/sys/mman.cc @@ -35,7 +35,7 @@ extern "C" void* __mmap2(void* addr, namespace { template <typename T> -T Align(T value, uint8_t alignment) { +T Align(T value, size_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } From eb3f371879bbf944c06224ef317149402cfd22a2 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 11 Jan 2019 12:51:00 -0500 Subject: [PATCH 122/401] mac: Update comment describing using Mach receive rights with kqueue() The prohibition on using Mach receive rights with kqueue() was lifted in 10.12. Add the source code reference that should have been here all along, and explain how xnu has changed. When the minimum runtime target is 10.12 or later, the port set in this code will be unnecessary, and it will be possible to remove it. Change-Id: I8fdf91a124efb081e4748ccf60680b12a38c4d18 Reviewed-on: https://chromium-review.googlesource.com/c/1406894 Reviewed-by: Robert Sesek <rsesek@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/mach/child_port_handshake.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/util/mach/child_port_handshake.cc b/util/mach/child_port_handshake.cc index a1918c02..1891f91d 100644 --- a/util/mach/child_port_handshake.cc +++ b/util/mach/child_port_handshake.cc @@ -126,8 +126,12 @@ mach_port_t ChildPortHandshakeServer::RunServer( return MACH_PORT_NULL; } - // A kqueue cannot monitor a raw Mach receive right with EVFILT_MACHPORT. It - // requires a port set. Create a new port set and add the receive right to it. + // Prior to macOS 10.12, a kqueue cannot monitor a raw Mach receive right with + // EVFILT_MACHPORT. It requires a port set. Compare 10.11.6 + // xnu-3248.60.10/osfmk/ipc/ipc_pset.c filt_machportattach(), which requires + // MACH_PORT_RIGHT_PORT_SET, to 10.12.0 xnu-3789.1.32/osfmk/ipc/ipc_pset.c + // filt_machportattach(), which also handles MACH_PORT_TYPE_RECEIVE. Create a + // new port set and add the receive right to it. base::mac::ScopedMachPortSet server_port_set( NewMachPort(MACH_PORT_RIGHT_PORT_SET)); CHECK(server_port_set.is_valid()); From d079df5587cdd978b06406824a6513f29cdca7cb Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 11 Jan 2019 11:29:31 -0800 Subject: [PATCH 123/401] android: use the correct architecture macro Bug: 912739 Change-Id: Ibc802ca2849ee89bd7965946297f3b0943cabfac Reviewed-on: https://chromium-review.googlesource.com/c/1406867 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client_linux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index ed1d7dfd..556a91fc 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -57,7 +57,7 @@ std::vector<std::string> BuildAppProcessArgs( const std::vector<std::string>& arguments, int socket) { std::vector<std::string> argv; -#if defined(ARCH_CPU_64_BIT) +#if defined(ARCH_CPU_64_BITS) argv.push_back("/system/bin/app_process64"); #else argv.push_back("/system/bin/app_process32"); From 25048d37f815595de218f7d1afad8f7c656544f6 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 11 Jan 2019 15:06:38 -0800 Subject: [PATCH 124/401] fuchsia: Remove log.cpp and log.h zx_log_ is being removed in favour of zx_debuglog_, and so log.h/cpp will also be going. Bug: fuchsia:ZX-2184 Change-Id: I4f342d05716745d1248fe1de6e7cd2f92ff1dea3 Reviewed-on: https://chromium-review.googlesource.com/c/1407534 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- third_party/fuchsia/BUILD.gn | 2 -- 1 file changed, 2 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index f2b8174d..1e6d94db 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -106,7 +106,6 @@ if (crashpad_is_in_fuchsia) { "$sdk_pkg_path/zx/include/lib/zx/handle.h", "$sdk_pkg_path/zx/include/lib/zx/interrupt.h", "$sdk_pkg_path/zx/include/lib/zx/job.h", - "$sdk_pkg_path/zx/include/lib/zx/log.h", "$sdk_pkg_path/zx/include/lib/zx/object.h", "$sdk_pkg_path/zx/include/lib/zx/object_traits.h", "$sdk_pkg_path/zx/include/lib/zx/pmt.h", @@ -122,7 +121,6 @@ if (crashpad_is_in_fuchsia) { "$sdk_pkg_path/zx/include/lib/zx/vmo.h", "$sdk_pkg_path/zx/interrupt.cpp", "$sdk_pkg_path/zx/job.cpp", - "$sdk_pkg_path/zx/log.cpp", "$sdk_pkg_path/zx/port.cpp", "$sdk_pkg_path/zx/process.cpp", "$sdk_pkg_path/zx/resource.cpp", From 922b5750c139981787edc7ba040be9fe0351f534 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 14 Dec 2018 14:07:56 -0800 Subject: [PATCH 125/401] fuchsia: Update for zx_task_suspend() supporting processes zx_task_suspend() now supports suspending processes. This is somewhat more reliable than suspending the constituent threads because after the call returns and the token is being held, any subsequently started threads will start in the the suspended state. However, because the suspend is asynchronous the threads of the process still need to be iterated to wait for them to assert ZX_THREAD_SUSPENDED (and that can and does still fail to happen for a number of reasons). So while improved, this class is still only best-effort. Additionally, as the version of ScopedTaskSuspend that took a thread wasn't being used, remove that. Bug: crashpad:269 Change-Id: Ifb3f8e0d780a5e22af33613f92a61d25459f5139 Reviewed-on: https://chromium-review.googlesource.com/c/1377201 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- util/fuchsia/scoped_task_suspend.cc | 41 ++++++++--------------------- util/fuchsia/scoped_task_suspend.h | 16 +++-------- 2 files changed, 15 insertions(+), 42 deletions(-) diff --git a/util/fuchsia/scoped_task_suspend.cc b/util/fuchsia/scoped_task_suspend.cc index 0daaf635..5d9f03ec 100644 --- a/util/fuchsia/scoped_task_suspend.cc +++ b/util/fuchsia/scoped_task_suspend.cc @@ -24,39 +24,20 @@ namespace crashpad { -namespace { - -// Returns the suspend token of the suspended thread. This function attempts -// to wait a short time for the thread to actually suspend before returning -// but this is not guaranteed. -zx::suspend_token SuspendThread(const zx::thread& thread) { - zx::suspend_token token; - zx_status_t status = thread.suspend(&token); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_task_suspend"; - return zx::suspend_token(); - } - - zx_signals_t observed = 0u; - if (thread.wait_one(ZX_THREAD_SUSPENDED, - zx::deadline_after(zx::msec(50)), - &observed) != ZX_OK) { - LOG(ERROR) << "thread failed to suspend"; - } - return token; -} - -} // namespace - ScopedTaskSuspend::ScopedTaskSuspend(const zx::process& process) { DCHECK_NE(process.get(), zx::process::self()->get()); - for (const auto& thread : GetThreadHandles(process)) - suspend_tokens_.push_back(SuspendThread(thread)); -} -ScopedTaskSuspend::ScopedTaskSuspend(const zx::thread& thread) { - DCHECK_NE(thread.get(), zx::thread::self()->get()); - suspend_tokens_.push_back(SuspendThread(thread)); + zx_status_t status = process.suspend(&suspend_token_); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_task_suspend"; + } else { + for (const auto& thread : GetThreadHandles(process)) { + zx_signals_t observed = 0u; + status = thread.wait_one( + ZX_THREAD_SUSPENDED, zx::deadline_after(zx::msec(50)), &observed); + ZX_LOG_IF(ERROR, status != ZX_OK, status) << "thread failed to suspend"; + } + } } } // namespace crashpad diff --git a/util/fuchsia/scoped_task_suspend.h b/util/fuchsia/scoped_task_suspend.h index 251904a8..afe497bc 100644 --- a/util/fuchsia/scoped_task_suspend.h +++ b/util/fuchsia/scoped_task_suspend.h @@ -27,27 +27,19 @@ namespace crashpad { //! \brief Manages the suspension of another task. //! -//! The underlying API only supports suspending threads (despite its name) not -//! entire tasks. As a result, it's possible some threads may not be correctly -//! suspended/resumed as their creation might race enumeration. -//! -//! Additionally, suspending a thread is asynchronous and may take an -//! arbitrary amount of time. -//! -//! Because of these limitations, this class is limited to being a best-effort, -//! and correct suspension/resumption cannot be relied upon. +//! Suspending a process is asynchronous, and may take an arbitrary amount of +//! time. As a result, this class is limited to being a best-effort, and +//! correct suspension/resumption cannot be relied upon. //! //! Callers should not attempt to suspend the current task as obtained via //! `zx_process_self()`. class ScopedTaskSuspend { public: explicit ScopedTaskSuspend(const zx::process& process); - explicit ScopedTaskSuspend(const zx::thread& thread); ~ScopedTaskSuspend() = default; private: - // Could be one (for a thread) or many (for every thread in a process). - std::vector<zx::suspend_token> suspend_tokens_; + zx::suspend_token suspend_token_; DISALLOW_COPY_AND_ASSIGN(ScopedTaskSuspend); }; From fe05eb7c99a42d0c1c437061fb5470f6fd844854 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 16 Jan 2019 09:18:18 -0800 Subject: [PATCH 126/401] Update ASan disabled tests to exclude all platforms Use-after-return detection happens to currently be enabled on Linux and Android but is not exclusive to those platforms. Disable tests incompatible with ASan UAR detection on all platforms. Bug: 915245 Change-Id: I40447c126dac9dc7d0f72e400136afb8c292324d Reviewed-on: https://chromium-review.googlesource.com/c/1414614 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- .../process_snapshot_sanitized_test.cc | 22 ++++--------------- util/misc/capture_context_test.cc | 8 +++---- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/snapshot/sanitized/process_snapshot_sanitized_test.cc b/snapshot/sanitized/process_snapshot_sanitized_test.cc index cb413e3b..f4c852f9 100644 --- a/snapshot/sanitized/process_snapshot_sanitized_test.cc +++ b/snapshot/sanitized/process_snapshot_sanitized_test.cc @@ -163,23 +163,9 @@ class StackSanitizationChecker : public MemorySnapshot::Delegate { // MemorySnapshot::Delegate bool MemorySnapshotDelegateRead(void* data, size_t size) override { -#if defined(ADDRESS_SANITIZER) && (defined(OS_LINUX) || defined(OS_ANDROID)) - // AddressSanitizer causes stack variables to be stored separately from the - // call stack. - auto addr_not_in_stack_range = - [](VMAddress addr, VMAddress stack_addr, VMSize stack_size) { - return addr < stack_addr || addr >= stack_addr + stack_size; - }; - EXPECT_PRED3(addr_not_in_stack_range, - addrs_.code_pointer_address, - stack_->Address(), - size); - EXPECT_PRED3(addr_not_in_stack_range, - addrs_.string_address, - stack_->Address(), - size); - return true; -#else + // AddressSanitizer with use-after-return detection causes stack variables + // to be allocated on the heap. +#if !defined(ADDRESS_SANITIZER) size_t pointer_offset; if (!AssignIfInRange(&pointer_offset, addrs_.code_pointer_address - stack_->Address())) { @@ -209,8 +195,8 @@ class StackSanitizationChecker : public MemorySnapshot::Delegate { } else { EXPECT_STREQ(string, kSensitiveStackData); } +#endif // !ADDRESS_SANITIZER return true; -#endif // ADDRESS_SANITIZER && (OS_LINUX || OS_ANDROID) } private: diff --git a/util/misc/capture_context_test.cc b/util/misc/capture_context_test.cc index 7f3890f1..7137a313 100644 --- a/util/misc/capture_context_test.cc +++ b/util/misc/capture_context_test.cc @@ -67,9 +67,9 @@ void TestCaptureContext() { // value can be the lowest value possible. NativeCPUContext context_2; -// AddressSanitizer on Linux causes stack variables to be stored separately from -// the call stack. -#if !defined(ADDRESS_SANITIZER) || (!defined(OS_LINUX) && !defined(OS_ANDROID)) + // AddressSanitizer with use-after-return detection causes stack variables to + // be allocated on the heap. +#if !defined(ADDRESS_SANITIZER) // The stack pointer reference value is the lowest address of a local variable // in this function. The captured program counter will be slightly less than // or equal to the reference stack pointer. @@ -82,7 +82,7 @@ void TestCaptureContext() { uintptr_t reference) { return reference - actual < 768u; }, sp, kReferenceSP); -#endif // !ADDRESS_SANITIZER || (!OS_LINUX && !OS_ANDROID) +#endif // !ADDRESS_SANITIZER // Capture the context again, expecting that the stack pointer stays the same // and the program counter increases. Strictly speaking, there’s no guarantee From 0dde0ef81c4b40770870715082035ddd0768fba0 Mon Sep 17 00:00:00 2001 From: Victor Costan <pwnall@chromium.org> Date: Fri, 18 Jan 2019 17:17:49 -0800 Subject: [PATCH 127/401] Add missing using statement in notify_server_test.cc. The test currently compile because of ADL (argument-dependent lookup). It does not compile with a more recent googletest version. See associated bug for linked to failed builds and compiler error messages. Bug: crashpad:274 Change-Id: I7f2dd736453deb2a1af7bcacefc421961e1eb95e Reviewed-on: https://chromium-review.googlesource.com/c/1422786 Commit-Queue: Victor Costan <pwnall@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- util/mach/notify_server_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/util/mach/notify_server_test.cc b/util/mach/notify_server_test.cc index b5e152db..d334e571 100644 --- a/util/mach/notify_server_test.cc +++ b/util/mach/notify_server_test.cc @@ -31,6 +31,7 @@ namespace test { namespace { using testing::AllOf; +using testing::DoAll; using testing::Eq; using testing::Invoke; using testing::Pointee; From 8694cbf33e88375ae27c02d4d44b044d546f356a Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 22 Jan 2019 14:17:16 -0500 Subject: [PATCH 128/401] Update gtest to 9518a57428ae0a7ed450c1361768e84a2a38af5a 4665eee10a1d test, please ignore 826656b25f62 Remove workarounds for unsupported MSVC versions c43603f288f4 Remove GTEST_HAS_HASH_SET/MAP check a3a42514f1a9 Define GTEST_DISABLE_MSC_WARNINGS_PUSH/POP for all compilers 48021336904c Add back warning suppression that shouldn't have been removed 1454f301c554 Update README.md 09beafcd1d54 Merge branch 'master' into patch-1 7a0680dc2230 Merge pull request #1959 from robinlinden:remove-msvc- workarounds d5932506d6ee Merge pull request #1961 from coppered/patch-1 c5f08bf91944 Googletest export e46e87bb1f76 Googletest export aac18185ebb4 Googletest export 8e86f6726164 Googletest export 45d66d81bec9 Googletest export 5dab7be70d62 Googletest export c2989fe29b6a Googletest export b49266606875 Googletest export bb7c0ecbdf47 Googletest export 64368e0584e0 Googletest export f7779eb3cb5d Googletest export a3013cceffbe Googletest export 3cf8f514d859 Update build badge ce526b87007a Issue #1955: Remove THREADS_PREFER_PTHREAD_FLAG 28a3261fdf94 Create CODE_OF_CONDUCT.md 87589af5ba5a Update .travis.yml 2f126c74d264 Update .travis.yml 5404fd7d06a8 Update .travis.yml 915f6cfef369 Update .travis.yml fca458cab75b Googletest export 191f9336bc92 Merge pull request #1977 from lukasm91:issue_1955_remove_pthread_flags b22d23667b60 Googletest export 8fbf9d16a63a Googletest export 775a17631217 Fixed typo a42cdf2abdc0 Googletest export 26743363be8f Googletest export ba344cbc405f Googletest export 10e82d01d94c Update README.md a28a71ae41fa Update README.md 214521a1486d Update WORKSPACE 3fd66989bb5c Googletest export 067aa4c28bb1 Do not define GTEST_IS_THREADSAFE within GTEST_HAS_SEH 3d71ab4c37de Googletest export fe14e3030737 Merge pull request #1995 from siddhanjay/patch-1 2c8ab3f18b2e feat: Add initial support for PlatformIO and Arduino 695cf7c96249 Merge pull request #1997 from gpakosz:GTEST_IS_THREADSAFE 39c09043b83e chore: Add initial library.json config d9251df84951 fix: Remove global chmod from Travis 31eb5e9b873a chore: Update version to latest release b5c08cb9f4f1 Cache gcc and clang APT packages 06bb8d4d6dcf Googletest export 6cbd3753dc19 Googletest export ea5e941d8470 Change directory ownership earlier fc0f92676865 Don't cache APT packages on OS X/macOS 3b1f43c2e7a5 Use if statements b545089f5117 Merge pull request #2004 from cotsog/patch-1 6ef591381372 Googletest export 3949c403c0ed Update README.md 81f00260668d Googletest export c6cb7e033591 Googletest export b5f5c596a991 Merge pull request #2000 from ciband:feat/add_support_platformio 1496f73cc4c3 fix: correct JSON syntax 0f698c830f79 chore: Add .vs to .gitignore for Visual Studio 096fb37a1976 Googletest export 1ec20f87e390 Googletest export b7dd66519f4a Googletest export ed3f9bb22960 Googletest export 85c4172ed66e Update README.md 7515e399436a Googletest export 9ab640ce5e51 Googletest export e26a3fa13ca2 Googletest export 9494c45e75a5 Googletest export a83cc11abe48 Googletest export b93a13ec4db4 Improvements have been made to the example/sample makefiles for both googlemock and googletest. Library files are now created and named like versions produced by Cmake 34a99e547ab7 Googletest export 4160336cb433 Merge pull request #2013 from ciband:chore/fix_library_json 150613166524 Update README.md c0ef2cbe42df fix: Correct GitHub paths 16269ae2f857 Merge pull request #2027 from ciband:chore/fix_library_json 77004096e850 Update README.md 6729a1361150 Merge #2002 0cf2130c0b59 Update Xcode project file 3bedb5a9fc36 Merge pull request #2035 from syohex/update-xcode-project- file 6d5ce40d4c27 fix: Add additional source and include directories de99386b67a3 Merge branch 'chore/fix_library_json' of https://github.com/ciband/googletest into chore/fix_library_json 25905b9f9a45 Merge branch 'master' of https://github.com/google/googletest 2ace910a3580 Revert "test, please ignore" 8ed34e0f6b4e Remove outdated scripts 933e5df28372 Merge pull request #2039 from gennadiycivil/master f8b1c1af1775 Googletest export 14c2fba7349e Googletest export 1bcbd5871e34 Merge pull request #2037 from ciband:chore/fix_library_json bfcc47fc2f61 Merge pull request #2026 from justin6case/example_makefile_improvements 8a27d164cbc7 Update README.md 6e410a3ae965 Update README.md ac8c102dae66 Update README.md 3a460a26b7a9 Googletest export 827515f8a092 Googletest export 5d3a2cd9c854 Update docs, TestCase->TestSuite 58e62f7a989c Merge branch 'master' of https://github.com/google/googletest 3880b13e4c0b Merge pull request #2042 from gennadiycivil/master ade8baa7d213 clang-tidy: modernize-deprecated-headers 8369b5bbd0dd fixing build errors for unused parameter b6cd405286ed Googletest export 644319b9f06f Merge pull request #2048 from ciband:chore/clang_tidy 216c37f057ae Googletest export f31bf1d362af Googletest export 50f1a77955bd Merge pull request #2051 from enptfb55:master 7a7e2bba1d62 Googletest export bc1023b4131c Googletest export 6693e85b0402 Merge branch 'master' of github.com:google/googletest 2edadcedf350 Workaround homebrew issue 0599a7b8410d Googletest export 097407fd3cfb Googletest export 9acd065a905a Googletest export eb9225ce361a Googletest export 0adeadd28302 Googletest export 9518a57428ae Googletest export Change-Id: I2029f907549bed52816fd3660be5b77ad19e73c9 Reviewed-on: https://chromium-review.googlesource.com/c/1427241 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- third_party/gtest/BUILD.gn | 13 +++++++++---- third_party/gtest/gmock.gyp | 8 ++++++-- third_party/gtest/gtest.gyp | 5 +++-- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/DEPS b/DEPS index 10c37bc3..0c8edf20 100644 --- a/DEPS +++ b/DEPS @@ -24,7 +24,7 @@ deps = { '6fe4a3251488f7af86d64fc25cf442e817cf6133', 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + - 'b18d39bd2ea2d2b508228a9a1d8ae9f7fba32f78', + '9518a57428ae0a7ed450c1361768e84a2a38af5a', 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f', diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index 541f6402..e124b9e7 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -56,6 +56,7 @@ if (crashpad_is_in_chromium) { testonly = true sources = [ "gtest/googletest/include/gtest/gtest-death-test.h", + "gtest/googletest/include/gtest/gtest-matchers.h", "gtest/googletest/include/gtest/gtest-message.h", "gtest/googletest/include/gtest/gtest-param-test.h", "gtest/googletest/include/gtest/gtest-printers.h", @@ -71,18 +72,17 @@ if (crashpad_is_in_chromium) { "gtest/googletest/include/gtest/internal/gtest-death-test-internal.h", "gtest/googletest/include/gtest/internal/gtest-filepath.h", "gtest/googletest/include/gtest/internal/gtest-internal.h", - "gtest/googletest/include/gtest/internal/gtest-linked_ptr.h", "gtest/googletest/include/gtest/internal/gtest-param-util-generated.h", "gtest/googletest/include/gtest/internal/gtest-param-util.h", "gtest/googletest/include/gtest/internal/gtest-port-arch.h", "gtest/googletest/include/gtest/internal/gtest-port.h", "gtest/googletest/include/gtest/internal/gtest-string.h", - "gtest/googletest/include/gtest/internal/gtest-tuple.h", "gtest/googletest/include/gtest/internal/gtest-type-util.h", "gtest/googletest/src/gtest-all.cc", "gtest/googletest/src/gtest-death-test.cc", "gtest/googletest/src/gtest-filepath.cc", "gtest/googletest/src/gtest-internal-inl.h", + "gtest/googletest/src/gtest-matchers.cc", "gtest/googletest/src/gtest-port.cc", "gtest/googletest/src/gtest-printers.cc", "gtest/googletest/src/gtest-test-part.cc", @@ -130,6 +130,7 @@ if (crashpad_is_in_chromium) { "gtest/googletest/test/gtest_main_unittest.cc", "gtest/googletest/test/gtest_pred_impl_unittest.cc", "gtest/googletest/test/gtest_prod_test.cc", + "gtest/googletest/test/gtest_skip_test.cc", "gtest/googletest/test/gtest_unittest.cc", "gtest/googletest/test/production.cc", "gtest/googletest/test/production.h", @@ -288,13 +289,14 @@ if (crashpad_is_in_chromium) { sources = [ "gtest/googlemock/include/gmock/gmock-actions.h", "gtest/googlemock/include/gmock/gmock-cardinalities.h", + "gtest/googlemock/include/gmock/gmock-function-mocker.h", "gtest/googlemock/include/gmock/gmock-generated-actions.h", "gtest/googlemock/include/gmock/gmock-generated-function-mockers.h", "gtest/googlemock/include/gmock/gmock-generated-matchers.h", - "gtest/googlemock/include/gmock/gmock-generated-nice-strict.h", "gtest/googlemock/include/gmock/gmock-matchers.h", "gtest/googlemock/include/gmock/gmock-more-actions.h", "gtest/googlemock/include/gmock/gmock-more-matchers.h", + "gtest/googlemock/include/gmock/gmock-nice-strict.h", "gtest/googlemock/include/gmock/gmock-spec-builders.h", "gtest/googlemock/include/gmock/gmock.h", "gtest/googlemock/include/gmock/internal/custom/gmock-generated-actions.h", @@ -303,6 +305,7 @@ if (crashpad_is_in_chromium) { "gtest/googlemock/include/gmock/internal/gmock-generated-internal-utils.h", "gtest/googlemock/include/gmock/internal/gmock-internal-utils.h", "gtest/googlemock/include/gmock/internal/gmock-port.h", + "gtest/googlemock/include/gmock/internal/gmock-pp.h", "gtest/googlemock/src/gmock-all.cc", "gtest/googlemock/src/gmock-cardinalities.cc", "gtest/googlemock/src/gmock-internal-utils.cc", @@ -338,15 +341,17 @@ if (crashpad_is_in_chromium) { sources = [ "gtest/googlemock/test/gmock-actions_test.cc", "gtest/googlemock/test/gmock-cardinalities_test.cc", + "gtest/googlemock/test/gmock-function-mocker_test.cc", "gtest/googlemock/test/gmock-generated-actions_test.cc", "gtest/googlemock/test/gmock-generated-function-mockers_test.cc", - "gtest/googlemock/test/gmock-generated-internal-utils_test.cc", "gtest/googlemock/test/gmock-generated-matchers_test.cc", "gtest/googlemock/test/gmock-internal-utils_test.cc", "gtest/googlemock/test/gmock-matchers_test.cc", "gtest/googlemock/test/gmock-more-actions_test.cc", "gtest/googlemock/test/gmock-nice-strict_test.cc", "gtest/googlemock/test/gmock-port_test.cc", + "gtest/googlemock/test/gmock-pp-string_test.cc", + "gtest/googlemock/test/gmock-pp_test.cc", "gtest/googlemock/test/gmock-spec-builders_test.cc", "gtest/googlemock/test/gmock_test.cc", ] diff --git a/third_party/gtest/gmock.gyp b/third_party/gtest/gmock.gyp index d53c925f..499792f9 100644 --- a/third_party/gtest/gmock.gyp +++ b/third_party/gtest/gmock.gyp @@ -56,18 +56,20 @@ 'sources': [ '<(gmock_dir)/include/gmock/gmock-actions.h', '<(gmock_dir)/include/gmock/gmock-cardinalities.h', + '<(gmock_dir)/include/gmock/gmock-function-mocker.h', '<(gmock_dir)/include/gmock/gmock-generated-actions.h', '<(gmock_dir)/include/gmock/gmock-generated-function-mockers.h', '<(gmock_dir)/include/gmock/gmock-generated-matchers.h', - '<(gmock_dir)/include/gmock/gmock-generated-nice-strict.h', '<(gmock_dir)/include/gmock/gmock-matchers.h', '<(gmock_dir)/include/gmock/gmock-more-actions.h', '<(gmock_dir)/include/gmock/gmock-more-matchers.h', + '<(gmock_dir)/include/gmock/gmock-nice-strict.h', '<(gmock_dir)/include/gmock/gmock-spec-builders.h', '<(gmock_dir)/include/gmock/gmock.h', '<(gmock_dir)/include/gmock/internal/custom/gmock-generated-actions.h', '<(gmock_dir)/include/gmock/internal/custom/gmock-matchers.h', '<(gmock_dir)/include/gmock/internal/custom/gmock-port.h', + '<(gmock_dir)/include/gmock/internal/custom/gmock-pp.h', '<(gmock_dir)/include/gmock/internal/gmock-generated-internal-utils.h', '<(gmock_dir)/include/gmock/internal/gmock-internal-utils.h', '<(gmock_dir)/include/gmock/internal/gmock-port.h', @@ -156,15 +158,17 @@ 'sources': [ '<(gmock_dir)/test/gmock-actions_test.cc', '<(gmock_dir)/test/gmock-cardinalities_test.cc', + '<(gmock_dir)/test/gmock-function-mocker_test.cc', '<(gmock_dir)/test/gmock-generated-actions_test.cc', '<(gmock_dir)/test/gmock-generated-function-mockers_test.cc', - '<(gmock_dir)/test/gmock-generated-internal-utils_test.cc', '<(gmock_dir)/test/gmock-generated-matchers_test.cc', '<(gmock_dir)/test/gmock-internal-utils_test.cc', '<(gmock_dir)/test/gmock-matchers_test.cc', '<(gmock_dir)/test/gmock-more-actions_test.cc', '<(gmock_dir)/test/gmock-nice-strict_test.cc', '<(gmock_dir)/test/gmock-port_test.cc', + '<(gmock_dir)/test/gmock-pp-string_test.cc', + '<(gmock_dir)/test/gmock-pp_test.cc', '<(gmock_dir)/test/gmock-spec-builders_test.cc', '<(gmock_dir)/test/gmock_test.cc', ], diff --git a/third_party/gtest/gtest.gyp b/third_party/gtest/gtest.gyp index 5d93feb5..aa6399bc 100644 --- a/third_party/gtest/gtest.gyp +++ b/third_party/gtest/gtest.gyp @@ -67,6 +67,7 @@ ], 'sources': [ '<(gtest_dir)/include/gtest/gtest-death-test.h', + '<(gtest_dir)/include/gtest/gtest-matchers.h', '<(gtest_dir)/include/gtest/gtest-message.h', '<(gtest_dir)/include/gtest/gtest-param-test.h', '<(gtest_dir)/include/gtest/gtest-printers.h', @@ -82,18 +83,17 @@ '<(gtest_dir)/include/gtest/internal/gtest-death-test-internal.h', '<(gtest_dir)/include/gtest/internal/gtest-filepath.h', '<(gtest_dir)/include/gtest/internal/gtest-internal.h', - '<(gtest_dir)/include/gtest/internal/gtest-linked_ptr.h', '<(gtest_dir)/include/gtest/internal/gtest-param-util-generated.h', '<(gtest_dir)/include/gtest/internal/gtest-param-util.h', '<(gtest_dir)/include/gtest/internal/gtest-port-arch.h', '<(gtest_dir)/include/gtest/internal/gtest-port.h', '<(gtest_dir)/include/gtest/internal/gtest-string.h', - '<(gtest_dir)/include/gtest/internal/gtest-tuple.h', '<(gtest_dir)/include/gtest/internal/gtest-type-util.h', '<(gtest_dir)/src/gtest-all.cc', '<(gtest_dir)/src/gtest-death-test.cc', '<(gtest_dir)/src/gtest-filepath.cc', '<(gtest_dir)/src/gtest-internal-inl.h', + '<(gtest_dir)/src/gtest-matchers.cc', '<(gtest_dir)/src/gtest-port.cc', '<(gtest_dir)/src/gtest-printers.cc', '<(gtest_dir)/src/gtest-test-part.cc', @@ -174,6 +174,7 @@ '<(gtest_dir)/test/gtest_main_unittest.cc', '<(gtest_dir)/test/gtest_pred_impl_unittest.cc', '<(gtest_dir)/test/gtest_prod_test.cc', + '<(gtest_dir)/test/gtest_skip_test.cc', '<(gtest_dir)/test/gtest_unittest.cc', '<(gtest_dir)/test/production.cc', '<(gtest_dir)/test/production.h', From 6a209070e46ade3b1f2ed065c6bb3af4f720a8de Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 22 Jan 2019 14:18:02 -0500 Subject: [PATCH 129/401] Change deprecated gtest TEST_CASE macros to TEST_SUITE No functional change. See https://github.com/google/googletest/blob/master/googletest/docs/primer.md#beware-of-the-nomenclature (as of 5d3a2cd9c854). Change-Id: I0f6dc59f014b01d18a09a92f016351a7402d8e6c Reviewed-on: https://chromium-review.googlesource.com/c/1427499 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- snapshot/crashpad_info_client_options_test.cc | 8 ++++---- util/misc/from_pointer_cast_test.cc | 2 +- util/net/http_body_test.cc | 6 +++--- util/net/http_transport_test.cc | 14 +++++++------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/snapshot/crashpad_info_client_options_test.cc b/snapshot/crashpad_info_client_options_test.cc index d1c5f9d3..1c5759eb 100644 --- a/snapshot/crashpad_info_client_options_test.cc +++ b/snapshot/crashpad_info_client_options_test.cc @@ -326,10 +326,10 @@ TEST_P(CrashpadInfoSizes_ClientOptions, DifferentlySizedStruct) { } } -INSTANTIATE_TEST_CASE_P(CrashpadInfoSizes_ClientOptions, - CrashpadInfoSizes_ClientOptions, - testing::Values(FILE_PATH_LITERAL("small"), - FILE_PATH_LITERAL("large"))); +INSTANTIATE_TEST_SUITE_P(CrashpadInfoSizes_ClientOptions, + CrashpadInfoSizes_ClientOptions, + testing::Values(FILE_PATH_LITERAL("small"), + FILE_PATH_LITERAL("large"))); } // namespace } // namespace test diff --git a/util/misc/from_pointer_cast_test.cc b/util/misc/from_pointer_cast_test.cc index 1a6850ff..ce53de54 100644 --- a/util/misc/from_pointer_cast_test.cc +++ b/util/misc/from_pointer_cast_test.cc @@ -41,7 +41,7 @@ using FromPointerCastTestTypes = testing::Types<void*, volatile SomeType*, const volatile SomeType*>; -TYPED_TEST_CASE(FromPointerCastTest, FromPointerCastTestTypes); +TYPED_TEST_SUITE(FromPointerCastTest, FromPointerCastTestTypes); TYPED_TEST(FromPointerCastTest, ToSigned) { EXPECT_EQ(FromPointerCast<int64_t>(nullptr), 0); diff --git a/util/net/http_body_test.cc b/util/net/http_body_test.cc index e48cbf91..1e5a4796 100644 --- a/util/net/http_body_test.cc +++ b/util/net/http_body_test.cc @@ -207,9 +207,9 @@ TEST_P(CompositeHTTPBodyStreamBufferSize, StringsAndFile) { EXPECT_EQ(actual_string, expected_string); } -INSTANTIATE_TEST_CASE_P(VariableBufferSize, - CompositeHTTPBodyStreamBufferSize, - testing::Values(1, 2, 9, 16, 31, 128, 1024)); +INSTANTIATE_TEST_SUITE_P(VariableBufferSize, + CompositeHTTPBodyStreamBufferSize, + testing::Values(1, 2, 9, 16, 31, 128, 1024)); } // namespace } // namespace test diff --git a/util/net/http_transport_test.cc b/util/net/http_transport_test.cc index 19422ec9..f7888c08 100644 --- a/util/net/http_transport_test.cc +++ b/util/net/http_transport_test.cc @@ -371,14 +371,14 @@ TEST_P(HTTPTransport, Upload33k_LengthUnknown) { // lacking libcrypto.so.1.1, so disabled there for now. On Mac, they could also // likely be enabled relatively easily, if HTTPTransportMac learned to respect // the user-supplied cert. -INSTANTIATE_TEST_CASE_P(HTTPTransport, - HTTPTransport, - testing::Values(FILE_PATH_LITERAL("http"), - FILE_PATH_LITERAL("https"))); +INSTANTIATE_TEST_SUITE_P(HTTPTransport, + HTTPTransport, + testing::Values(FILE_PATH_LITERAL("http"), + FILE_PATH_LITERAL("https"))); #else -INSTANTIATE_TEST_CASE_P(HTTPTransport, - HTTPTransport, - testing::Values(FILE_PATH_LITERAL("http"))); +INSTANTIATE_TEST_SUITE_P(HTTPTransport, + HTTPTransport, + testing::Values(FILE_PATH_LITERAL("http"))); #endif } // namespace From 79f4a3970a6425ef0475263974bf9a012279ba4f Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 22 Jan 2019 14:18:24 -0500 Subject: [PATCH 130/401] Use GTEST_SKIP() instead of custom DISABLED_TEST() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since gtest 00938b2b228f3, gtest has built-in first-class support for skipping tests, which is functionally identical (at least in Crashpad’s usage) to the home-grown support for run-time dynamically disabled tests introduced in Crashpad 5e9ed4cb9f69. Use the new standard pattern, and remove all vestiges of the custom local one. Change-Id: Ia332136c356d523885fc5d86bc8f06fefbe6a792 Reviewed-on: https://chromium-review.googlesource.com/c/1427242 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- client/crash_report_database_test.cc | 5 +- snapshot/win/exception_snapshot_win_test.cc | 5 +- snapshot/win/extra_memory_ranges_test.cc | 5 +- snapshot/win/module_snapshot_win_test.cc | 5 +- snapshot/win/process_snapshot_win_test.cc | 3 +- test/BUILD.gn | 2 - test/gtest_disabled.cc | 83 -------------------- test/gtest_disabled.h | 87 --------------------- test/gtest_main.cc | 3 - test/test.gyp | 2 - util/file/directory_reader_test.cc | 5 +- util/file/filesystem_test.cc | 13 ++- util/win/process_info_test.cc | 3 +- 13 files changed, 18 insertions(+), 203 deletions(-) delete mode 100644 test/gtest_disabled.cc delete mode 100644 test/gtest_disabled.h diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index 2dbb4fc1..76276abf 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" @@ -673,7 +672,7 @@ 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(); + GTEST_SKIP(); #else std::unique_ptr<CrashReportDatabase::NewReport> new_report; ASSERT_EQ(db()->PrepareNewCrashReport(&new_report), @@ -719,7 +718,7 @@ TEST_F(CrashReportDatabaseTest, Attachments) { TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { #if defined(OS_MACOSX) || defined(OS_WIN) // Attachments aren't supported on Mac and Windows yet. - DISABLED_TEST(); + 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. diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index 486e6df3..b4c44a83 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -23,7 +23,6 @@ #include "gtest/gtest.h" #include "snapshot/win/process_snapshot_win.h" #include "test/errors.h" -#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -176,7 +175,7 @@ TEST(ExceptionSnapshotWinTest, MAYBE_ChildCrash) { #if defined(ARCH_CPU_64_BITS) TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestCrashingChild(TestPaths::Architecture::k32Bit); @@ -293,7 +292,7 @@ TEST(SimulateCrash, MAYBE_ChildDumpWithoutCrashing) { #if defined(ARCH_CPU_64_BITS) TEST(SimulateCrash, ChildDumpWithoutCrashingWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestDumpWithoutCrashingChild(TestPaths::Architecture::k32Bit); diff --git a/snapshot/win/extra_memory_ranges_test.cc b/snapshot/win/extra_memory_ranges_test.cc index dcef8055..e0c17a20 100644 --- a/snapshot/win/extra_memory_ranges_test.cc +++ b/snapshot/win/extra_memory_ranges_test.cc @@ -25,7 +25,6 @@ #include "client/simple_address_range_bag.h" #include "gtest/gtest.h" #include "snapshot/win/process_snapshot_win.h" -#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -110,7 +109,7 @@ TEST(ExtraMemoryRanges, CrashDebugBreak) { #if defined(ARCH_CPU_64_BITS) TEST(ExtraMemoryRanges, DontCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestExtraMemoryRanges(kDontCrash, TestPaths::Architecture::k32Bit); @@ -118,7 +117,7 @@ TEST(ExtraMemoryRanges, DontCrashWOW64) { TEST(ExtraMemoryRanges, CrashDebugBreakWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Architecture::k32Bit); diff --git a/snapshot/win/module_snapshot_win_test.cc b/snapshot/win/module_snapshot_win_test.cc index 6a14cf5e..d9786cfd 100644 --- a/snapshot/win/module_snapshot_win_test.cc +++ b/snapshot/win/module_snapshot_win_test.cc @@ -30,7 +30,6 @@ #include "snapshot/annotation_snapshot.h" #include "snapshot/win/pe_image_reader.h" #include "snapshot/win/process_reader_win.h" -#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -152,7 +151,7 @@ TEST(ModuleSnapshotWinTest, CrashDebugBreak) { #if defined(ARCH_CPU_64_BITS) TEST(ModuleSnapshotWinTest, DontCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::k32Bit); @@ -160,7 +159,7 @@ TEST(ModuleSnapshotWinTest, DontCrashWOW64) { TEST(ModuleSnapshotWinTest, CrashDebugBreakWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::k32Bit); diff --git a/snapshot/win/process_snapshot_win_test.cc b/snapshot/win/process_snapshot_win_test.cc index 8a3e6a49..7192aa85 100644 --- a/snapshot/win/process_snapshot_win_test.cc +++ b/snapshot/win/process_snapshot_win_test.cc @@ -20,7 +20,6 @@ #include "snapshot/win/pe_image_reader.h" #include "snapshot/win/process_reader_win.h" #include "test/errors.h" -#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -120,7 +119,7 @@ TEST(ProcessSnapshotTest, CrashpadInfoChild) { #if defined(ARCH_CPU_64_BITS) TEST(ProcessSnapshotTest, CrashpadInfoChildWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestImageReaderChild(TestPaths::Architecture::k32Bit); diff --git a/test/BUILD.gn b/test/BUILD.gn index bded2c60..24f8d991 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -25,8 +25,6 @@ static_library("test") { "filesystem.cc", "filesystem.h", "gtest_death.h", - "gtest_disabled.cc", - "gtest_disabled.h", "hex_string.cc", "hex_string.h", "main_arguments.cc", diff --git a/test/gtest_disabled.cc b/test/gtest_disabled.cc deleted file mode 100644 index fab6802a..00000000 --- a/test/gtest_disabled.cc +++ /dev/null @@ -1,83 +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 "test/gtest_disabled.h" - -#include <stdio.h> - -#include "base/format_macros.h" -#include "base/logging.h" -#include "base/strings/stringprintf.h" - -namespace crashpad { -namespace test { - -namespace { - -DisabledTestGtestEnvironment* g_instance; - -} // namespace - -// static -DisabledTestGtestEnvironment* DisabledTestGtestEnvironment::Get() { - if (!g_instance) { - g_instance = new DisabledTestGtestEnvironment(); - } - return g_instance; -} - -void DisabledTestGtestEnvironment::DisabledTest() { - const testing::TestInfo* test_info = - testing::UnitTest::GetInstance()->current_test_info(); - std::string disabled_test = base::StringPrintf( - "%s.%s", test_info->test_case_name(), test_info->name()); - - // Show a DISABLED message using a format similar to gtest, along with a hint - // explaining that OK or FAILED will also appear. - printf( - "This test has been disabled dynamically.\n" - "It will appear as both DISABLED and OK or FAILED.\n" - "[ DISABLED ] %s\n", - disabled_test.c_str()); - - disabled_tests_.push_back(disabled_test); -} - -DisabledTestGtestEnvironment::DisabledTestGtestEnvironment() - : testing::Environment(), - disabled_tests_() { - DCHECK(!g_instance); -} - -DisabledTestGtestEnvironment::~DisabledTestGtestEnvironment() { - DCHECK_EQ(this, g_instance); - g_instance = nullptr; -} - -void DisabledTestGtestEnvironment::TearDown() { - if (!disabled_tests_.empty()) { - printf( - "[ DISABLED ] %" PRIuS " dynamically disabled test%s, listed below:\n" - "[ DISABLED ] %s also counted in PASSED or FAILED below.\n", - disabled_tests_.size(), - disabled_tests_.size() == 1 ? "" : "s", - disabled_tests_.size() == 1 ? "This test is" : "These tests are"); - for (const std::string& disabled_test : disabled_tests_) { - printf("[ DISABLED ] %s\n", disabled_test.c_str()); - } - } -} - -} // namespace test -} // namespace crashpad diff --git a/test/gtest_disabled.h b/test/gtest_disabled.h deleted file mode 100644 index 9415cba2..00000000 --- a/test/gtest_disabled.h +++ /dev/null @@ -1,87 +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. - -#ifndef CRASHPAD_TEST_GTEST_DISABLED_H_ -#define CRASHPAD_TEST_GTEST_DISABLED_H_ - -#include <string> -#include <vector> - -#include "base/macros.h" -#include "gtest/gtest.h" - -//! \file - -namespace crashpad { -namespace test { - -//! \brief Provides support for dynamically disabled gtest tests. -//! -//! A test runner must register this with gtest as follows prior to calling -//! `RUN_ALL_TESTS()`: -//! \code -//! testing::AddGlobalTestEnvironment( -//! crashpad::test::DisabledTestGtestEnvironment::Get()); -//! \endcode -class DisabledTestGtestEnvironment final : public testing::Environment { - public: - //! \brief Returns the DisabledTestGtestEnvironment singleton instance, - //! creating it if necessary. - static DisabledTestGtestEnvironment* Get(); - - //! \brief Displays a message about a test being disabled, and arranges for - //! this information to be duplicated in TearDown(). - //! - //! This method is for the internal use of the DISABLED_TEST() macro. Do not - //! call it directly, use the macro instead. - void DisabledTest(); - - private: - DisabledTestGtestEnvironment(); - ~DisabledTestGtestEnvironment() override; - - // testing::Environment: - void TearDown() override; - - std::vector<std::string> disabled_tests_; - - DISALLOW_COPY_AND_ASSIGN(DisabledTestGtestEnvironment); -}; - -} // namespace test -} // namespace crashpad - -//! \brief Displays a message about a test being disabled, and returns early. -//! -//! gtest only provides a mechanism for tests to be disabled statically, by -//! prefixing test case names or test names with `DISABLED_`. When it is -//! necessary to disable tests dynamically, gtest provides no assistance. This -//! macro displays a message about the disabled test and returns early. The -//! dynamically disabled test will also be displayed during gtest global test -//! environment tear-down before the test executable exits. -//! -//! This macro may only be invoked from the context of a gtest test. -//! -//! There’s a long-standing <a -//! href="https://groups.google.com/d/topic/googletestframework/Nwh3u7YFuN4">gtest -//! feature request</a> to provide this functionality directly in gtest, but -//! since it hasn’t been implemented, this macro provides a local mechanism to -//! achieve it. -#define DISABLED_TEST() \ - do { \ - ::crashpad::test::DisabledTestGtestEnvironment::Get()->DisabledTest(); \ - return; \ - } while (false) - -#endif // CRASHPAD_TEST_GTEST_DISABLED_H_ diff --git a/test/gtest_main.cc b/test/gtest_main.cc index ebdbeb9d..5a54691f 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -14,7 +14,6 @@ #include "build/build_config.h" #include "gtest/gtest.h" -#include "test/gtest_disabled.h" #include "test/main_arguments.h" #include "test/multiprocess_exec.h" @@ -51,8 +50,6 @@ bool GetChildTestFunctionName(std::string* child_func_name) { int main(int argc, char* argv[]) { crashpad::test::InitializeMainArguments(argc, argv); - testing::AddGlobalTestEnvironment( - crashpad::test::DisabledTestGtestEnvironment::Get()); std::string child_func_name; if (GetChildTestFunctionName(&child_func_name)) { diff --git a/test/test.gyp b/test/test.gyp index 8101f8f2..d00256a7 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -37,8 +37,6 @@ 'filesystem.cc', 'filesystem.h', 'gtest_death.h', - 'gtest_disabled.cc', - 'gtest_disabled.h', 'hex_string.cc', 'hex_string.h', 'linux/fake_ptrace_connection.cc', diff --git a/util/file/directory_reader_test.cc b/util/file/directory_reader_test.cc index f03669e2..812deaf1 100644 --- a/util/file/directory_reader_test.cc +++ b/util/file/directory_reader_test.cc @@ -22,7 +22,6 @@ #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.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" @@ -48,7 +47,7 @@ TEST(DirectoryReader, BadPaths) { TEST(DirectoryReader, BadPaths_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -144,7 +143,7 @@ TEST(DirectoryReader, FilesAndDirectories) { TEST(DirectoryReader, FilesAndDirectories_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestFilesAndDirectories(true); diff --git a/util/file/filesystem_test.cc b/util/file/filesystem_test.cc index 3430c3f9..37a9290b 100644 --- a/util/file/filesystem_test.cc +++ b/util/file/filesystem_test.cc @@ -21,7 +21,6 @@ #include "gtest/gtest.h" #include "test/errors.h" #include "test/filesystem.h" -#include "test/gtest_disabled.h" #include "test/scoped_temp_dir.h" #include "util/misc/time.h" @@ -93,7 +92,7 @@ TEST(Filesystem, FileModificationTime) { TEST(Filesystem, FileModificationTime_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -224,7 +223,7 @@ TEST(Filesystem, MoveFileOrDirectory) { TEST(Filesystem, MoveFileOrDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -302,7 +301,7 @@ TEST(Filesystem, IsRegularFile) { TEST(Filesystem, IsRegularFile_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -344,7 +343,7 @@ TEST(Filesystem, IsDirectory) { TEST(Filesystem, IsDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -393,7 +392,7 @@ TEST(Filesystem, RemoveFile) { TEST(Filesystem, RemoveFile_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -450,7 +449,7 @@ TEST(Filesystem, RemoveDirectory) { TEST(Filesystem, RemoveDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc index c7abdb6f..601a2938 100644 --- a/util/win/process_info_test.cc +++ b/util/win/process_info_test.cc @@ -26,7 +26,6 @@ #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" -#include "test/gtest_disabled.h" #include "test/scoped_temp_dir.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" @@ -202,7 +201,7 @@ TEST(ProcessInfo, OtherProcess) { #if defined(ARCH_CPU_64_BITS) TEST(ProcessInfo, OtherProcessWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestOtherProcess(TestPaths::Architecture::k32Bit); From 1fc95dc3ccb6d2a0a54e50aa9f4f55c01551cd7d Mon Sep 17 00:00:00 2001 From: Matthew Dempsky <mdempsky@chromium.org> Date: Thu, 17 Jan 2019 17:47:13 -0800 Subject: [PATCH 131/401] [fuchsia] Add zx_vmo_replace_as_executable to tests Fuchsia in the future will create VMOs as non-executable (i.e., without ZX_RIGHT_EXECUTE) by default, so this necessary preparation for that. Change-Id: I00ada804d1d16db4f50ff3882058e382b1845328 Reviewed-on: https://chromium-review.googlesource.com/c/1419778 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Matthew Dempsky <mdempsky@chromium.org> --- snapshot/fuchsia/process_snapshot_fuchsia_test.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc index a96d37c0..52215a78 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc @@ -58,6 +58,8 @@ CRASHPAD_CHILD_TEST_MAIN(AddressSpaceChildTestMain) { const size_t size = t.pages * 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); + ZX_CHECK(status == ZX_OK, status) << "zx_vmo_replace_as_executable"; uintptr_t mapping_addr = 0; status = zx_vmar_map( zx_vmar_root_self(), t.zircon_perm, 0, vmo, 0, size, &mapping_addr); From f66a125cd592b22465f7c32dbe6ddc2e5e2cc276 Mon Sep 17 00:00:00 2001 From: Eric Astor <epastor@google.com> Date: Mon, 28 Jan 2019 10:19:44 -0500 Subject: [PATCH 132/401] Move POSIX-only include into #ifdef guard, preventing warnings of undefined symbols in some conservative build configurations. Change-Id: I75ab0a7623c506a826b42406484e8a29f9db9304 Reviewed-on: https://chromium-review.googlesource.com/c/1439198 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Eric Astor <epastor@google.com> --- tools/generate_dump.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/generate_dump.cc b/tools/generate_dump.cc index 9fb5a961..35a4e05a 100644 --- a/tools/generate_dump.cc +++ b/tools/generate_dump.cc @@ -26,11 +26,12 @@ #include "minidump/minidump_file_writer.h" #include "tools/tool_support.h" #include "util/file/file_writer.h" -#include "util/posix/drop_privileges.h" #include "util/stdlib/string_number_conversion.h" #if defined(OS_POSIX) #include <unistd.h> + +#include "util/posix/drop_privileges.h" #endif #if defined(OS_MACOSX) From 84ef87ef510942883b99ef8d7a0e292945ff8696 Mon Sep 17 00:00:00 2001 From: Tom Tan <Tom.Tan@microsoft.com> Date: Tue, 5 Feb 2019 11:13:29 -0800 Subject: [PATCH 133/401] Fix arm64 CONTEXT for crashy_test_program Bug: chromium:893460 Change-Id: I0bd47521d68aa9477e32104986bd7aeb1d4e2738 Reviewed-on: https://chromium-review.googlesource.com/c/1454820 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- handler/win/crashy_test_program.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/handler/win/crashy_test_program.cc b/handler/win/crashy_test_program.cc index 990929bf..9c8adbbd 100644 --- a/handler/win/crashy_test_program.cc +++ b/handler/win/crashy_test_program.cc @@ -101,7 +101,7 @@ DWORD WINAPI NullThreadProc(void* param) { return 0; } -// Creates a suspended background thread, and sets EDI/RDI to point at +// Creates a suspended background thread, and sets EDI/RDI/X17 to point at // g_test_memory so we can confirm it's available in the minidump. bool CreateThreadWithRegisterPointingToTestMemory() { HANDLE thread = CreateThread( @@ -121,6 +121,8 @@ bool CreateThreadWithRegisterPointingToTestMemory() { context.Rdi = reinterpret_cast<DWORD64>(g_test_memory); #elif defined(ARCH_CPU_X86) context.Edi = reinterpret_cast<DWORD>(g_test_memory); +#elif defined(ARCH_CPU_ARM64) + context.X17 = reinterpret_cast<DWORD64>(g_test_memory); #endif if (!SetThreadContext(thread, &context)) { PLOG(ERROR) << "SetThreadContext"; From caad799c28f267c9d33d680b2298826cd6336480 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 6 Feb 2019 12:43:50 -0800 Subject: [PATCH 134/401] Delete chromium-specific macOS rpaths These flags are no longer tracked here since the macOS crashpad_handler is built upstream as of https://crrev.com/629713 Bug: chromium:912286 Change-Id: I6735a6a1364086e67d1b7c2d316829c74c20d0d9 Reviewed-on: https://chromium-review.googlesource.com/c/1456777 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- handler/BUILD.gn | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 7a91b1c3..32d4d6c1 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -135,29 +135,6 @@ crashpad_executable("crashpad_handler") { "../third_party/mini_chromium:base", ] - if (crashpad_is_mac && crashpad_is_in_chromium) { - if (is_component_build) { - ldflags = [ - # The handler is in - # Chromium.app/Contents/Versions/X/Chromium Framework.framework/Versions/A/Helpers/ - # so set rpath up to the base. - "-rpath", - "@loader_path/../../../../../../../..", - - # The handler is also in - # Content Shell.app/Contents/Frameworks/Content Shell Framework.framework/Versions/C/Helpers/ - # so set the rpath for that too. - "-rpath", - "@loader_path/../../../../../../..", - - # The handler can also be executed in an unbundled framework at - # Chromium Framework.framework/Versions/A/Helpers/ - "-rpath", - "@loader_path/../../../..", - ] - } - } - if (crashpad_is_win) { if (crashpad_is_in_chromium || crashpad_is_in_dart) { remove_configs = [ "//build/config/win:console" ] From 152aa8d1f9039b2ac61339bcd8d8f6030ffbcea7 Mon Sep 17 00:00:00 2001 From: Maksim Sisov <msisov@igalia.com> Date: Tue, 5 Feb 2019 08:33:45 +0200 Subject: [PATCH 135/401] Add missing limits header to crashpad. This patch fixes the following error: ../../third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc:246:12: error: 'numeric_limits' is not a member of 'std' std::numeric_limits<decltype(context->spsr)>::max()) { ^~~~~~~~~~~~~~ ../../third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc:246:27: error: expected primary-expression before 'decltype' std::numeric_limits<decltype(context->spsr)>::max()) { ^~~~~~~~ ../../third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc:246:27: error: expected ')' before 'decltype' Bug: chromium:819294 Change-Id: I4f31a33fcdae9567c71a4d371d2e6afe68d2ef6a Reviewed-on: https://chromium-review.googlesource.com/c/1454376 Commit-Queue: Maksim Sisov <msisov@igalia.com> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- snapshot/linux/cpu_context_linux.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snapshot/linux/cpu_context_linux.cc b/snapshot/linux/cpu_context_linux.cc index 6ba52a8d..8464a5a2 100644 --- a/snapshot/linux/cpu_context_linux.cc +++ b/snapshot/linux/cpu_context_linux.cc @@ -17,6 +17,8 @@ #include <stddef.h> #include <string.h> +#include <limits> + #include "base/logging.h" namespace crashpad { From ff5a25e11f5578bdd9997d416fa6e1492e4463f3 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 11 Feb 2019 10:59:14 -0500 Subject: [PATCH 136/401] Remove a few unnecessary semicolons. Patch by Nico Weber <thakis@chromium.org>, originally https://crrev.com/c/1463405. Bug: chromium:926235 Change-Id: I7e0ba822aa8dd104768d7ad6e603539576ae96a9 Reviewed-on: https://chromium-review.googlesource.com/c/1463744 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Nico Weber <thakis@chromium.org> --- minidump/minidump_user_stream_writer.cc | 2 +- snapshot/crashpad_types/crashpad_info_reader.cc | 16 ++++++++-------- snapshot/elf/elf_image_reader_test.cc | 4 ++-- snapshot/minidump/minidump_stream.h | 2 +- test/multiprocess.h | 2 +- test/multiprocess_exec_test.cc | 5 ++--- util/linux/memory_map.cc | 2 +- util/misc/lexing.cc | 8 ++++---- 8 files changed, 20 insertions(+), 21 deletions(-) diff --git a/minidump/minidump_user_stream_writer.cc b/minidump/minidump_user_stream_writer.cc index 139e8270..8401b285 100644 --- a/minidump/minidump_user_stream_writer.cc +++ b/minidump/minidump_user_stream_writer.cc @@ -42,7 +42,7 @@ class MinidumpUserStreamWriter::SnapshotContentsWriter final return snapshot_->Read(this); } - size_t GetSize() const override { return snapshot_ ? snapshot_->Size() : 0; }; + size_t GetSize() const override { return snapshot_ ? snapshot_->Size() : 0; } bool MemorySnapshotDelegateRead(void* data, size_t size) override { return writer_->Write(data, size); diff --git a/snapshot/crashpad_types/crashpad_info_reader.cc b/snapshot/crashpad_types/crashpad_info_reader.cc index 527d3723..07a9b48e 100644 --- a/snapshot/crashpad_types/crashpad_info_reader.cc +++ b/snapshot/crashpad_types/crashpad_info_reader.cc @@ -160,29 +160,29 @@ bool CrashpadInfoReader::Initialize(const ProcessMemoryRange* memory, return GET_MEMBER(member); \ } -DEFINE_GETTER(TriState, CrashpadHandlerBehavior, crashpad_handler_behavior); +DEFINE_GETTER(TriState, CrashpadHandlerBehavior, crashpad_handler_behavior) DEFINE_GETTER(TriState, SystemCrashReporterForwarding, - system_crash_reporter_forwarding); + system_crash_reporter_forwarding) DEFINE_GETTER(TriState, GatherIndirectlyReferencedMemory, - gather_indirectly_referenced_memory); + gather_indirectly_referenced_memory) DEFINE_GETTER(uint32_t, IndirectlyReferencedMemoryCap, - indirectly_referenced_memory_cap); + indirectly_referenced_memory_cap) -DEFINE_GETTER(VMAddress, ExtraMemoryRanges, extra_memory_ranges); +DEFINE_GETTER(VMAddress, ExtraMemoryRanges, extra_memory_ranges) -DEFINE_GETTER(VMAddress, SimpleAnnotations, simple_annotations); +DEFINE_GETTER(VMAddress, SimpleAnnotations, simple_annotations) -DEFINE_GETTER(VMAddress, AnnotationsList, annotations_list); +DEFINE_GETTER(VMAddress, AnnotationsList, annotations_list) DEFINE_GETTER(VMAddress, UserDataMinidumpStreamHead, - user_data_minidump_stream_head); + user_data_minidump_stream_head) #undef DEFINE_GETTER #undef GET_MEMBER diff --git a/snapshot/elf/elf_image_reader_test.cc b/snapshot/elf/elf_image_reader_test.cc index 0846ada4..971ed229 100644 --- a/snapshot/elf/elf_image_reader_test.cc +++ b/snapshot/elf/elf_image_reader_test.cc @@ -49,8 +49,8 @@ #endif // OS_FUCHSIA extern "C" { -__attribute__((visibility("default"))) void -ElfImageReaderTestExportedSymbol(){}; +__attribute__((visibility("default"))) void ElfImageReaderTestExportedSymbol() { +} } // extern "C" namespace crashpad { diff --git a/snapshot/minidump/minidump_stream.h b/snapshot/minidump/minidump_stream.h index 1c75cb63..4356b2c6 100644 --- a/snapshot/minidump/minidump_stream.h +++ b/snapshot/minidump/minidump_stream.h @@ -25,7 +25,7 @@ namespace crashpad { class MinidumpStream { public: MinidumpStream(uint32_t stream_type, std::vector<uint8_t> data) - : stream_type_(stream_type), data_(data){}; + : stream_type_(stream_type), data_(data) {} uint32_t stream_type() const { return stream_type_; } const std::vector<uint8_t>& data() const { return data_; } diff --git a/test/multiprocess.h b/test/multiprocess.h index d0275020..9a221bb3 100644 --- a/test/multiprocess.h +++ b/test/multiprocess.h @@ -26,7 +26,7 @@ namespace test { namespace internal { struct MultiprocessInfo; -}; +} // namespace internal //! \brief Manages a multiprocess test. //! diff --git a/test/multiprocess_exec_test.cc b/test/multiprocess_exec_test.cc index 99a1b01f..d290efa8 100644 --- a/test/multiprocess_exec_test.cc +++ b/test/multiprocess_exec_test.cc @@ -72,8 +72,7 @@ TEST(MultiprocessExec, MultiprocessExecSimpleChild) { TestMultiprocessExec exec; exec.SetChildTestMainFunction("SimpleMultiprocess"); exec.Run(); -}; - +} CRASHPAD_CHILD_TEST_MAIN(SimpleMultiprocessReturnsNonZero) { return 123; @@ -96,7 +95,7 @@ TEST(MultiprocessExec, MultiprocessExecSimpleChildReturnsNonZero) { exec.SetExpectedChildTermination( Multiprocess::TerminationReason::kTerminationNormal, 123); exec.Run(); -}; +} #if !defined(OS_WIN) diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index 4f02ce88..17fd7a3d 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -210,7 +210,7 @@ ParseResult ParseMapsLine(DelimitedFileReader* maps_file_reader, class SparseReverseIterator : public MemoryMap::Iterator { public: SparseReverseIterator(const std::vector<const MemoryMap::Mapping*>& mappings) - : mappings_(mappings), riter_(mappings_.rbegin()){}; + : mappings_(mappings), riter_(mappings_.rbegin()) {} SparseReverseIterator() : mappings_(), riter_(mappings_.rend()) {} diff --git a/util/misc/lexing.cc b/util/misc/lexing.cc index 6c318654..5e8fa304 100644 --- a/util/misc/lexing.cc +++ b/util/misc/lexing.cc @@ -32,10 +32,10 @@ namespace { bool ConvertStringToNumber(const base::StringPiece& input, type* value) { \ return function(input, value); \ } -MAKE_ADAPTER(int, base::StringToInt); -MAKE_ADAPTER(unsigned int, base::StringToUint); -MAKE_ADAPTER(int64_t, base::StringToInt64); -MAKE_ADAPTER(uint64_t, base::StringToUint64); +MAKE_ADAPTER(int, base::StringToInt) +MAKE_ADAPTER(unsigned int, base::StringToUint) +MAKE_ADAPTER(int64_t, base::StringToInt64) +MAKE_ADAPTER(uint64_t, base::StringToUint64) #undef MAKE_ADAPTER } // namespace From bba9d0819c12a4bf39bebafb6233e000aa8a446c Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 11 Feb 2019 11:36:58 -0500 Subject: [PATCH 137/401] Revert "Use GTEST_SKIP() instead of custom DISABLED_TEST()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 79f4a3970a6425ef0475263974bf9a012279ba4f. Chromium’s test launcher is not prepared to handle GTEST_SKIP(). Bug: chromium:912138 Change-Id: Iaeffaedcd92093ec61b013f2a919dc4670094581 Reviewed-on: https://chromium-review.googlesource.com/c/1464099 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- client/crash_report_database_test.cc | 5 +- snapshot/win/exception_snapshot_win_test.cc | 5 +- snapshot/win/extra_memory_ranges_test.cc | 5 +- snapshot/win/module_snapshot_win_test.cc | 5 +- snapshot/win/process_snapshot_win_test.cc | 3 +- test/BUILD.gn | 2 + test/gtest_disabled.cc | 83 ++++++++++++++++++++ test/gtest_disabled.h | 87 +++++++++++++++++++++ test/gtest_main.cc | 3 + test/test.gyp | 2 + util/file/directory_reader_test.cc | 5 +- util/file/filesystem_test.cc | 13 +-- util/win/process_info_test.cc | 3 +- 13 files changed, 203 insertions(+), 18 deletions(-) create mode 100644 test/gtest_disabled.cc create mode 100644 test/gtest_disabled.h diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index 76276abf..2dbb4fc1 100644 --- a/client/crash_report_database_test.cc +++ b/client/crash_report_database_test.cc @@ -20,6 +20,7 @@ #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" @@ -672,7 +673,7 @@ 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(); + DISABLED_TEST(); #else std::unique_ptr<CrashReportDatabase::NewReport> new_report; ASSERT_EQ(db()->PrepareNewCrashReport(&new_report), @@ -718,7 +719,7 @@ TEST_F(CrashReportDatabaseTest, Attachments) { TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { #if defined(OS_MACOSX) || defined(OS_WIN) // Attachments aren't supported on Mac and Windows yet. - GTEST_SKIP(); + 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. diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index b4c44a83..486e6df3 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -23,6 +23,7 @@ #include "gtest/gtest.h" #include "snapshot/win/process_snapshot_win.h" #include "test/errors.h" +#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -175,7 +176,7 @@ TEST(ExceptionSnapshotWinTest, MAYBE_ChildCrash) { #if defined(ARCH_CPU_64_BITS) TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - GTEST_SKIP(); + DISABLED_TEST(); } TestCrashingChild(TestPaths::Architecture::k32Bit); @@ -292,7 +293,7 @@ TEST(SimulateCrash, MAYBE_ChildDumpWithoutCrashing) { #if defined(ARCH_CPU_64_BITS) TEST(SimulateCrash, ChildDumpWithoutCrashingWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - GTEST_SKIP(); + DISABLED_TEST(); } TestDumpWithoutCrashingChild(TestPaths::Architecture::k32Bit); diff --git a/snapshot/win/extra_memory_ranges_test.cc b/snapshot/win/extra_memory_ranges_test.cc index e0c17a20..dcef8055 100644 --- a/snapshot/win/extra_memory_ranges_test.cc +++ b/snapshot/win/extra_memory_ranges_test.cc @@ -25,6 +25,7 @@ #include "client/simple_address_range_bag.h" #include "gtest/gtest.h" #include "snapshot/win/process_snapshot_win.h" +#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -109,7 +110,7 @@ TEST(ExtraMemoryRanges, CrashDebugBreak) { #if defined(ARCH_CPU_64_BITS) TEST(ExtraMemoryRanges, DontCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - GTEST_SKIP(); + DISABLED_TEST(); } TestExtraMemoryRanges(kDontCrash, TestPaths::Architecture::k32Bit); @@ -117,7 +118,7 @@ TEST(ExtraMemoryRanges, DontCrashWOW64) { TEST(ExtraMemoryRanges, CrashDebugBreakWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - GTEST_SKIP(); + DISABLED_TEST(); } TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Architecture::k32Bit); diff --git a/snapshot/win/module_snapshot_win_test.cc b/snapshot/win/module_snapshot_win_test.cc index d9786cfd..6a14cf5e 100644 --- a/snapshot/win/module_snapshot_win_test.cc +++ b/snapshot/win/module_snapshot_win_test.cc @@ -30,6 +30,7 @@ #include "snapshot/annotation_snapshot.h" #include "snapshot/win/pe_image_reader.h" #include "snapshot/win/process_reader_win.h" +#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -151,7 +152,7 @@ TEST(ModuleSnapshotWinTest, CrashDebugBreak) { #if defined(ARCH_CPU_64_BITS) TEST(ModuleSnapshotWinTest, DontCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - GTEST_SKIP(); + DISABLED_TEST(); } TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::k32Bit); @@ -159,7 +160,7 @@ TEST(ModuleSnapshotWinTest, DontCrashWOW64) { TEST(ModuleSnapshotWinTest, CrashDebugBreakWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - GTEST_SKIP(); + DISABLED_TEST(); } TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::k32Bit); diff --git a/snapshot/win/process_snapshot_win_test.cc b/snapshot/win/process_snapshot_win_test.cc index 7192aa85..8a3e6a49 100644 --- a/snapshot/win/process_snapshot_win_test.cc +++ b/snapshot/win/process_snapshot_win_test.cc @@ -20,6 +20,7 @@ #include "snapshot/win/pe_image_reader.h" #include "snapshot/win/process_reader_win.h" #include "test/errors.h" +#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -119,7 +120,7 @@ TEST(ProcessSnapshotTest, CrashpadInfoChild) { #if defined(ARCH_CPU_64_BITS) TEST(ProcessSnapshotTest, CrashpadInfoChildWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - GTEST_SKIP(); + DISABLED_TEST(); } TestImageReaderChild(TestPaths::Architecture::k32Bit); diff --git a/test/BUILD.gn b/test/BUILD.gn index 24f8d991..bded2c60 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -25,6 +25,8 @@ static_library("test") { "filesystem.cc", "filesystem.h", "gtest_death.h", + "gtest_disabled.cc", + "gtest_disabled.h", "hex_string.cc", "hex_string.h", "main_arguments.cc", diff --git a/test/gtest_disabled.cc b/test/gtest_disabled.cc new file mode 100644 index 00000000..fab6802a --- /dev/null +++ b/test/gtest_disabled.cc @@ -0,0 +1,83 @@ +// 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 "test/gtest_disabled.h" + +#include <stdio.h> + +#include "base/format_macros.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" + +namespace crashpad { +namespace test { + +namespace { + +DisabledTestGtestEnvironment* g_instance; + +} // namespace + +// static +DisabledTestGtestEnvironment* DisabledTestGtestEnvironment::Get() { + if (!g_instance) { + g_instance = new DisabledTestGtestEnvironment(); + } + return g_instance; +} + +void DisabledTestGtestEnvironment::DisabledTest() { + const testing::TestInfo* test_info = + testing::UnitTest::GetInstance()->current_test_info(); + std::string disabled_test = base::StringPrintf( + "%s.%s", test_info->test_case_name(), test_info->name()); + + // Show a DISABLED message using a format similar to gtest, along with a hint + // explaining that OK or FAILED will also appear. + printf( + "This test has been disabled dynamically.\n" + "It will appear as both DISABLED and OK or FAILED.\n" + "[ DISABLED ] %s\n", + disabled_test.c_str()); + + disabled_tests_.push_back(disabled_test); +} + +DisabledTestGtestEnvironment::DisabledTestGtestEnvironment() + : testing::Environment(), + disabled_tests_() { + DCHECK(!g_instance); +} + +DisabledTestGtestEnvironment::~DisabledTestGtestEnvironment() { + DCHECK_EQ(this, g_instance); + g_instance = nullptr; +} + +void DisabledTestGtestEnvironment::TearDown() { + if (!disabled_tests_.empty()) { + printf( + "[ DISABLED ] %" PRIuS " dynamically disabled test%s, listed below:\n" + "[ DISABLED ] %s also counted in PASSED or FAILED below.\n", + disabled_tests_.size(), + disabled_tests_.size() == 1 ? "" : "s", + disabled_tests_.size() == 1 ? "This test is" : "These tests are"); + for (const std::string& disabled_test : disabled_tests_) { + printf("[ DISABLED ] %s\n", disabled_test.c_str()); + } + } +} + +} // namespace test +} // namespace crashpad diff --git a/test/gtest_disabled.h b/test/gtest_disabled.h new file mode 100644 index 00000000..9415cba2 --- /dev/null +++ b/test/gtest_disabled.h @@ -0,0 +1,87 @@ +// 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. + +#ifndef CRASHPAD_TEST_GTEST_DISABLED_H_ +#define CRASHPAD_TEST_GTEST_DISABLED_H_ + +#include <string> +#include <vector> + +#include "base/macros.h" +#include "gtest/gtest.h" + +//! \file + +namespace crashpad { +namespace test { + +//! \brief Provides support for dynamically disabled gtest tests. +//! +//! A test runner must register this with gtest as follows prior to calling +//! `RUN_ALL_TESTS()`: +//! \code +//! testing::AddGlobalTestEnvironment( +//! crashpad::test::DisabledTestGtestEnvironment::Get()); +//! \endcode +class DisabledTestGtestEnvironment final : public testing::Environment { + public: + //! \brief Returns the DisabledTestGtestEnvironment singleton instance, + //! creating it if necessary. + static DisabledTestGtestEnvironment* Get(); + + //! \brief Displays a message about a test being disabled, and arranges for + //! this information to be duplicated in TearDown(). + //! + //! This method is for the internal use of the DISABLED_TEST() macro. Do not + //! call it directly, use the macro instead. + void DisabledTest(); + + private: + DisabledTestGtestEnvironment(); + ~DisabledTestGtestEnvironment() override; + + // testing::Environment: + void TearDown() override; + + std::vector<std::string> disabled_tests_; + + DISALLOW_COPY_AND_ASSIGN(DisabledTestGtestEnvironment); +}; + +} // namespace test +} // namespace crashpad + +//! \brief Displays a message about a test being disabled, and returns early. +//! +//! gtest only provides a mechanism for tests to be disabled statically, by +//! prefixing test case names or test names with `DISABLED_`. When it is +//! necessary to disable tests dynamically, gtest provides no assistance. This +//! macro displays a message about the disabled test and returns early. The +//! dynamically disabled test will also be displayed during gtest global test +//! environment tear-down before the test executable exits. +//! +//! This macro may only be invoked from the context of a gtest test. +//! +//! There’s a long-standing <a +//! href="https://groups.google.com/d/topic/googletestframework/Nwh3u7YFuN4">gtest +//! feature request</a> to provide this functionality directly in gtest, but +//! since it hasn’t been implemented, this macro provides a local mechanism to +//! achieve it. +#define DISABLED_TEST() \ + do { \ + ::crashpad::test::DisabledTestGtestEnvironment::Get()->DisabledTest(); \ + return; \ + } while (false) + +#endif // CRASHPAD_TEST_GTEST_DISABLED_H_ diff --git a/test/gtest_main.cc b/test/gtest_main.cc index 5a54691f..ebdbeb9d 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -14,6 +14,7 @@ #include "build/build_config.h" #include "gtest/gtest.h" +#include "test/gtest_disabled.h" #include "test/main_arguments.h" #include "test/multiprocess_exec.h" @@ -50,6 +51,8 @@ bool GetChildTestFunctionName(std::string* child_func_name) { int main(int argc, char* argv[]) { crashpad::test::InitializeMainArguments(argc, argv); + testing::AddGlobalTestEnvironment( + crashpad::test::DisabledTestGtestEnvironment::Get()); std::string child_func_name; if (GetChildTestFunctionName(&child_func_name)) { diff --git a/test/test.gyp b/test/test.gyp index d00256a7..8101f8f2 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -37,6 +37,8 @@ 'filesystem.cc', 'filesystem.h', 'gtest_death.h', + 'gtest_disabled.cc', + 'gtest_disabled.h', 'hex_string.cc', 'hex_string.h', 'linux/fake_ptrace_connection.cc', diff --git a/util/file/directory_reader_test.cc b/util/file/directory_reader_test.cc index 812deaf1..f03669e2 100644 --- a/util/file/directory_reader_test.cc +++ b/util/file/directory_reader_test.cc @@ -22,6 +22,7 @@ #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.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" @@ -47,7 +48,7 @@ TEST(DirectoryReader, BadPaths) { TEST(DirectoryReader, BadPaths_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - GTEST_SKIP(); + DISABLED_TEST(); } ScopedTempDir temp_dir; @@ -143,7 +144,7 @@ TEST(DirectoryReader, FilesAndDirectories) { TEST(DirectoryReader, FilesAndDirectories_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - GTEST_SKIP(); + DISABLED_TEST(); } TestFilesAndDirectories(true); diff --git a/util/file/filesystem_test.cc b/util/file/filesystem_test.cc index 37a9290b..3430c3f9 100644 --- a/util/file/filesystem_test.cc +++ b/util/file/filesystem_test.cc @@ -21,6 +21,7 @@ #include "gtest/gtest.h" #include "test/errors.h" #include "test/filesystem.h" +#include "test/gtest_disabled.h" #include "test/scoped_temp_dir.h" #include "util/misc/time.h" @@ -92,7 +93,7 @@ TEST(Filesystem, FileModificationTime) { TEST(Filesystem, FileModificationTime_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - GTEST_SKIP(); + DISABLED_TEST(); } ScopedTempDir temp_dir; @@ -223,7 +224,7 @@ TEST(Filesystem, MoveFileOrDirectory) { TEST(Filesystem, MoveFileOrDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - GTEST_SKIP(); + DISABLED_TEST(); } ScopedTempDir temp_dir; @@ -301,7 +302,7 @@ TEST(Filesystem, IsRegularFile) { TEST(Filesystem, IsRegularFile_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - GTEST_SKIP(); + DISABLED_TEST(); } ScopedTempDir temp_dir; @@ -343,7 +344,7 @@ TEST(Filesystem, IsDirectory) { TEST(Filesystem, IsDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - GTEST_SKIP(); + DISABLED_TEST(); } ScopedTempDir temp_dir; @@ -392,7 +393,7 @@ TEST(Filesystem, RemoveFile) { TEST(Filesystem, RemoveFile_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - GTEST_SKIP(); + DISABLED_TEST(); } ScopedTempDir temp_dir; @@ -449,7 +450,7 @@ TEST(Filesystem, RemoveDirectory) { TEST(Filesystem, RemoveDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - GTEST_SKIP(); + DISABLED_TEST(); } ScopedTempDir temp_dir; diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc index 601a2938..c7abdb6f 100644 --- a/util/win/process_info_test.cc +++ b/util/win/process_info_test.cc @@ -26,6 +26,7 @@ #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" +#include "test/gtest_disabled.h" #include "test/scoped_temp_dir.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" @@ -201,7 +202,7 @@ TEST(ProcessInfo, OtherProcess) { #if defined(ARCH_CPU_64_BITS) TEST(ProcessInfo, OtherProcessWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - GTEST_SKIP(); + DISABLED_TEST(); } TestOtherProcess(TestPaths::Architecture::k32Bit); From 4dbd8c75d5243c6bc5512455d44bb49065773660 Mon Sep 17 00:00:00 2001 From: Petr Hosek <phosek@google.com> Date: Wed, 13 Feb 2019 19:22:23 -0800 Subject: [PATCH 138/401] Fix issues revealed by -ftrivial-auto-var-init=pattern -ftrivial-auto-var-init=pattern automatically initializes all variables with a pattern. This revealed two issues: 1. Unitialized read of field from CrashpadInfoClientOptions. 2. The PC distance check in TestCaptureContext (due to additional instrumentation, the distance is now 76 on x86-64 and 92 on aarch64). Change-Id: I528e5f21c70d2849c9300776da783fde59411e9e Reviewed-on: https://chromium-review.googlesource.com/c/1471691 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Nico Weber <thakis@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- snapshot/crashpad_info_client_options.cc | 3 ++- util/misc/capture_context_test.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/snapshot/crashpad_info_client_options.cc b/snapshot/crashpad_info_client_options.cc index 4a89d84a..fe3b0b38 100644 --- a/snapshot/crashpad_info_client_options.cc +++ b/snapshot/crashpad_info_client_options.cc @@ -39,7 +39,8 @@ TriState CrashpadInfoClientOptions::TriStateFromCrashpadInfo( CrashpadInfoClientOptions::CrashpadInfoClientOptions() : crashpad_handler_behavior(TriState::kUnset), system_crash_reporter_forwarding(TriState::kUnset), - gather_indirectly_referenced_memory(TriState::kUnset) { + gather_indirectly_referenced_memory(TriState::kUnset), + indirectly_referenced_memory_cap(0) { } } // namespace crashpad diff --git a/util/misc/capture_context_test.cc b/util/misc/capture_context_test.cc index 7137a313..42ce6ea2 100644 --- a/util/misc/capture_context_test.cc +++ b/util/misc/capture_context_test.cc @@ -55,7 +55,7 @@ void TestCaptureContext() { const uintptr_t kReferencePC = reinterpret_cast<uintptr_t>(TestCaptureContext); EXPECT_PRED2([](uintptr_t actual, - uintptr_t reference) { return actual - reference < 64u; }, + uintptr_t reference) { return actual - reference < 128u; }, pc, kReferencePC); #endif // !defined(ADDRESS_SANITIZER) From 03850fb6cf8436b542db6df1c7f285036eca5369 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 19 Feb 2019 10:28:27 -0500 Subject: [PATCH 139/401] Remove the last two extraneous semicolons Patch by Nico Weber <thakis@chromium.org>, originally https://crrev.com/c/1476986. Bug: chromium:926235 Change-Id: I6fd9aed5c57ffe0fec8f9adcd4cf5211d7b795c3 Reviewed-on: https://chromium-review.googlesource.com/c/1475992 Commit-Queue: Mark Mentovai <mark@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org> Reviewed-by: Nico Weber <thakis@chromium.org> --- minidump/minidump_extensions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h index bdaaa483..67157449 100644 --- a/minidump/minidump_extensions.h +++ b/minidump/minidump_extensions.h @@ -30,7 +30,7 @@ // compiler is buggy and only supports disabling it with a pragma, so we can't // disable it with other silly warnings in build/common.gypi. See: // https://connect.microsoft.com/VisualStudio/feedback/details/1114440 -MSVC_PUSH_DISABLE_WARNING(4200); +MSVC_PUSH_DISABLE_WARNING(4200) #if defined(COMPILER_MSVC) #define PACKED @@ -501,7 +501,7 @@ struct ALIGNAS(4) PACKED MinidumpCrashpadInfo { #endif // COMPILER_MSVC #undef PACKED -MSVC_POP_WARNING(); // C4200 +MSVC_POP_WARNING() // C4200 } // namespace crashpad From 25ba1d6895c13db487ec465775efca050d7f69e7 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 20 Feb 2019 13:18:05 -0800 Subject: [PATCH 140/401] Explicitly check mach_vm_read() size out parameter Explicitly check that mach_vm_read() successfully read the entire requested region. This is a speculative fix for an infrequent crash that occurs in the wild where only part of the region read by ReadMapped() was actually mapped into memory. Bug: chromium:918626 Change-Id: I4f4b3902d11480dc4a003608cfb1d371ec89425b Reviewed-on: https://chromium-review.googlesource.com/c/1455170 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/process/process_memory_mac.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/util/process/process_memory_mac.cc b/util/process/process_memory_mac.cc index eba1f201..29357f3d 100644 --- a/util/process/process_memory_mac.cc +++ b/util/process/process_memory_mac.cc @@ -94,8 +94,16 @@ std::unique_ptr<ProcessMemoryMac::MappedMemory> ProcessMemoryMac::ReadMapped( "mach_vm_read(0x%llx, 0x%llx)", region_address, region_size); return std::unique_ptr<MappedMemory>(); } + if (region_count != region_size) { + LOG(ERROR) << base::StringPrintf( + "mach_vm_read() unexpected read: 0x%x != 0x%llx bytes", + region_count, + region_size); + if (region_count) + vm_deallocate(mach_task_self(), region, region_count); + return std::unique_ptr<MappedMemory>(); + } - DCHECK_EQ(region_count, region_size); return std::unique_ptr<MappedMemory>( new MappedMemory(region, region_size, address - region_address, size)); } From 39e458b331b7ea09a20b1efbc001dee82b203bf2 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Thu, 21 Feb 2019 10:41:28 -0500 Subject: [PATCH 141/401] Remove (a? the last?) extraneous semicolon Bug: chromium:926235 Change-Id: Ie30810641c1d0dcc735002443f7a18facd9508a8 Reviewed-on: https://chromium-review.googlesource.com/c/1475993 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Nico Weber <thakis@chromium.org> --- client/crash_report_database.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/crash_report_database.h b/client/crash_report_database.h index d115c74b..1d6a9ed0 100644 --- a/client/crash_report_database.h +++ b/client/crash_report_database.h @@ -163,7 +163,7 @@ class CrashReportDatabase { //! This is not implemented on macOS or Windows. std::map<std::string, FileReader*> GetAttachments() const { return attachment_map_; - }; + } private: friend class CrashReportDatabase; From b1739cc67f577cdff66e368547c9353ce2d53e1c Mon Sep 17 00:00:00 2001 From: Nico Weber <thakis@chromium.org> Date: Fri, 22 Feb 2019 11:44:17 -0500 Subject: [PATCH 142/401] crashpad: Remove semicolons, Windows edition. Bug: chromium:926235 Change-Id: I392675c2f6ad09fbdabbb19c49805f73fa665c7e Reviewed-on: https://chromium-review.googlesource.com/c/1483310 Commit-Queue: Nico Weber <thakis@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/win/process_reader_win_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapshot/win/process_reader_win_test.cc b/snapshot/win/process_reader_win_test.cc index 1880c871..de220081 100644 --- a/snapshot/win/process_reader_win_test.cc +++ b/snapshot/win/process_reader_win_test.cc @@ -130,7 +130,7 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess { void ThreadMain() override { done_->Wait(); - }; + } private: Semaphore* done_; From 9d26012e9c73aa22e6746b9a8e77f4e9f74a60f7 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 22 Feb 2019 18:08:01 -0500 Subject: [PATCH 143/401] =?UTF-8?q?POSIX:=20don=E2=80=99t=20be=20overly=20?= =?UTF-8?q?restrictive=20about=20mmap()=20region=20length?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ScopedMmap was asserting that the length of a mapped region must be an exact number of pages, but this is not required or useful. Change-Id: I6141712a1980a217565e31ddcd4c23cf6a32503c Reviewed-on: https://chromium-review.googlesource.com/c/1480440 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/posix/scoped_mmap.cc | 6 ++- util/posix/scoped_mmap_test.cc | 88 ++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/util/posix/scoped_mmap.cc b/util/posix/scoped_mmap.cc index 4860cecb..0965fd67 100644 --- a/util/posix/scoped_mmap.cc +++ b/util/posix/scoped_mmap.cc @@ -19,6 +19,7 @@ #include <algorithm> #include "base/logging.h" +#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_math.h" namespace { @@ -54,9 +55,12 @@ bool ScopedMmap::ResetAddrLen(void* addr, size_t len) { if (addr == MAP_FAILED) { DCHECK_EQ(len, 0u); } else { + // Round |len| up to the next page. + const size_t kPageMask = base::checked_cast<size_t>(getpagesize()) - 1; + len = (len + kPageMask) & ~kPageMask; + DCHECK_NE(len, 0u); DCHECK_EQ(new_addr % getpagesize(), 0u); - DCHECK_EQ(len % getpagesize(), 0u); DCHECK((base::CheckedNumeric<uintptr_t>(new_addr) + (len - 1)).IsValid()); } diff --git a/util/posix/scoped_mmap_test.cc b/util/posix/scoped_mmap_test.cc index 5c69e7e4..e32fa159 100644 --- a/util/posix/scoped_mmap_test.cc +++ b/util/posix/scoped_mmap_test.cc @@ -294,6 +294,94 @@ TEST(ScopedMmapDeathTest, ResetMmap) { EXPECT_DEATH_CRASH(cookie.Check(), ""); } +TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { + ScopedMmap mapping; + EXPECT_FALSE(mapping.is_valid()); + EXPECT_EQ(mapping.addr(), MAP_FAILED); + EXPECT_EQ(mapping.len(), 0u); + + ASSERT_TRUE(mapping.Reset()); + EXPECT_FALSE(mapping.is_valid()); + + // Establishing a half-page mapping actually establishes a single page. + const size_t kPageSize = base::checked_cast<size_t>(getpagesize()); + const size_t kHalfPageSize = kPageSize / 2; + ASSERT_TRUE(ScopedMmapResetMmap(&mapping, kHalfPageSize)); + EXPECT_TRUE(mapping.is_valid()); + EXPECT_NE(mapping.addr(), MAP_FAILED); + EXPECT_EQ(mapping.len(), kPageSize); + + TestCookie cookie; + cookie.SetUp(mapping.addr_as<uint64_t*>()); + + // Shrinking a one-page mapping to a half page is a no-op. + void* orig_addr = mapping.addr(); + ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kHalfPageSize)); + EXPECT_TRUE(mapping.is_valid()); + EXPECT_EQ(mapping.addr(), orig_addr); + EXPECT_EQ(mapping.len(), kPageSize); + + EXPECT_EQ(cookie.Observed(), cookie.Expected()); + + // Same thing shrinking it to a single byte, or one byte less than a whole + // page. + ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, 1)); + EXPECT_TRUE(mapping.is_valid()); + EXPECT_EQ(mapping.addr(), orig_addr); + EXPECT_EQ(mapping.len(), kPageSize); + + EXPECT_EQ(cookie.Observed(), cookie.Expected()); + + ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kPageSize - 1)); + EXPECT_TRUE(mapping.is_valid()); + EXPECT_EQ(mapping.addr(), orig_addr); + EXPECT_EQ(mapping.len(), kPageSize); + + EXPECT_EQ(cookie.Observed(), cookie.Expected()); + + // Shrinking a two-page mapping to a half page frees the second page but + // leaves the first alone. + ASSERT_TRUE(ScopedMmapResetMmap(&mapping, 2 * kPageSize)); + EXPECT_TRUE(mapping.is_valid()); + EXPECT_NE(mapping.addr(), MAP_FAILED); + EXPECT_EQ(mapping.len(), 2 * kPageSize); + + TestCookie two_cookies[2]; + for (size_t index = 0; index < base::size(two_cookies); ++index) { + two_cookies[index].SetUp(reinterpret_cast<uint64_t*>( + mapping.addr_as<uintptr_t>() + index * kPageSize)); + } + + orig_addr = mapping.addr(); + ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kHalfPageSize)); + EXPECT_TRUE(mapping.is_valid()); + EXPECT_EQ(mapping.addr(), orig_addr); + EXPECT_EQ(mapping.len(), kPageSize); + + EXPECT_EQ(two_cookies[0].Observed(), two_cookies[0].Expected()); + EXPECT_DEATH_CRASH(two_cookies[1].Check(), ""); + + // Shrinking a two-page mapping to a page and a half is a no-op. + ASSERT_TRUE(ScopedMmapResetMmap(&mapping, 2 * kPageSize)); + EXPECT_TRUE(mapping.is_valid()); + EXPECT_NE(mapping.addr(), MAP_FAILED); + EXPECT_EQ(mapping.len(), 2 * kPageSize); + + for (size_t index = 0; index < base::size(two_cookies); ++index) { + two_cookies[index].SetUp(reinterpret_cast<uint64_t*>( + mapping.addr_as<uintptr_t>() + index * kPageSize)); + } + + orig_addr = mapping.addr(); + ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kPageSize + kHalfPageSize)); + EXPECT_TRUE(mapping.is_valid()); + EXPECT_EQ(mapping.addr(), orig_addr); + EXPECT_EQ(mapping.len(), 2 * kPageSize); + + EXPECT_EQ(two_cookies[0].Observed(), two_cookies[0].Expected()); + EXPECT_EQ(two_cookies[1].Observed(), two_cookies[1].Expected()); +} + TEST(ScopedMmapDeathTest, Mprotect) { ScopedMmap mapping; From dc17650336ad65d7d5de3dfd23909f8ac551f54a Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Mon, 25 Feb 2019 08:31:11 -0800 Subject: [PATCH 144/401] fuchsia: Update MultiprocessExec.BuiltinTrapTermination for task kill revamp Transitional CL until ZX_TASK_RETCODE_EXCEPTION_KILL lands, which will define various ZX_TASK_RETCODE_xxx values. Change-Id: Ia3b6a4bd9a05798721b92e0b72b9beeedc0f5f27 Reviewed-on: https://chromium-review.googlesource.com/c/1486891 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- test/multiprocess.h | 14 +++++++++++--- test/multiprocess_exec_fuchsia.cc | 12 ++++++++++-- test/multiprocess_exec_win.cc | 2 +- test/multiprocess_posix.cc | 2 +- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/test/multiprocess.h b/test/multiprocess.h index 9a221bb3..61df98b5 100644 --- a/test/multiprocess.h +++ b/test/multiprocess.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_TEST_MULTIPROCESS_H_ #define CRASHPAD_TEST_MULTIPROCESS_H_ +#include <stdint.h> #include <sys/types.h> #include "base/macros.h" @@ -28,6 +29,12 @@ namespace internal { struct MultiprocessInfo; } // namespace internal +#if defined(OS_FUCHSIA) +using ReturnCodeType = int64_t; +#else +using ReturnCodeType = int; +#endif + //! \brief Manages a multiprocess test. //! //! These tests are `fork()`-based. The parent and child processes are able to @@ -76,7 +83,7 @@ class Multiprocess { //! \brief Sets the expected termination reason and code. //! - //! The default expected termination reasaon is + //! The default expected termination reason is //! TerminationReason::kTerminationNormal, and the default expected //! termination code is `EXIT_SUCCESS` (`0`). //! @@ -91,7 +98,8 @@ class Multiprocess { //! TerminationReason::kTerminationSignal, this is the signal that is //! expected to kill the child. On Linux platforms, SIG_DFL will be //! installed for \a code in the child process. - void SetExpectedChildTermination(TerminationReason reason, int code); + void SetExpectedChildTermination(TerminationReason reason, + ReturnCodeType code); #if !defined(OS_WIN) //! \brief Sets termination reason and code appropriately for a child that @@ -211,7 +219,7 @@ class Multiprocess { virtual void MultiprocessChild() = 0; internal::MultiprocessInfo* info_; - int code_; + ReturnCodeType code_; TerminationReason reason_; DISALLOW_COPY_AND_ASSIGN(Multiprocess); diff --git a/test/multiprocess_exec_fuchsia.cc b/test/multiprocess_exec_fuchsia.cc index 9c68b7fd..eff522b0 100644 --- a/test/multiprocess_exec_fuchsia.cc +++ b/test/multiprocess_exec_fuchsia.cc @@ -87,7 +87,7 @@ void Multiprocess::Run() { } void Multiprocess::SetExpectedChildTermination(TerminationReason reason, - int code) { + ReturnCodeType code) { EXPECT_EQ(info_, nullptr) << "SetExpectedChildTermination() must be called before Run()"; reason_ = reason; @@ -95,7 +95,15 @@ void Multiprocess::SetExpectedChildTermination(TerminationReason reason, } void Multiprocess::SetExpectedChildTerminationBuiltinTrap() { - SetExpectedChildTermination(kTerminationNormal, -1); + // TODO(scottmg): Once + // https://fuchsia-review.googlesource.com/c/fuchsia/+/256771 lands, remove + // this #ifdef, and always use ZX_TASK_RETCODE_EXCEPTION_KILL. +#if defined(ZX_TASK_RETCODE_EXCEPTION_KILL) + constexpr ReturnCodeType kExpectedReturnCode = ZX_TASK_RETCODE_EXCEPTION_KILL; +#else + constexpr ReturnCodeType kExpectedReturnCode = -1; +#endif + SetExpectedChildTermination(kTerminationNormal, kExpectedReturnCode); } Multiprocess::~Multiprocess() { diff --git a/test/multiprocess_exec_win.cc b/test/multiprocess_exec_win.cc index 38978186..b75f8f57 100644 --- a/test/multiprocess_exec_win.cc +++ b/test/multiprocess_exec_win.cc @@ -58,7 +58,7 @@ void Multiprocess::Run() { } void Multiprocess::SetExpectedChildTermination(TerminationReason reason, - int code) { + ReturnCodeType code) { EXPECT_EQ(info_, nullptr) << "SetExpectedChildTermination() must be called before Run()"; reason_ = reason; diff --git a/test/multiprocess_posix.cc b/test/multiprocess_posix.cc index 2e0c3856..d2de3184 100644 --- a/test/multiprocess_posix.cc +++ b/test/multiprocess_posix.cc @@ -154,7 +154,7 @@ void Multiprocess::Run() { } void Multiprocess::SetExpectedChildTermination(TerminationReason reason, - int code) { + ReturnCodeType code) { EXPECT_EQ(info_, nullptr) << "SetExpectedChildTermination() must be called before Run()"; reason_ = reason; From 99bf283e54d049b6f5d2ad5522c6e3094b7156b4 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 21 Feb 2019 17:26:25 -0800 Subject: [PATCH 145/401] android: Add methods to start handler with /system/bin/linker Starting with Android Q, Bionic's linker will support loading executables from an APK, replacing the /system/bin/app_process workaround. libhandler_trampoline.so is a small executable, which `dlopen()`s the handler code from another native library allowing de-duplicating shared code with that library without having that library available for a more direct link time dependency. Bug: 928422 Change-Id: Ib126b8fca6005a34b9e4ef103eb1383dc0c554ea Reviewed-on: https://chromium-review.googlesource.com/c/1477336 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client.h | 91 +++++++++++++++++++++++++++++ client/crashpad_client_linux.cc | 85 +++++++++++++++++++++++++++ handler/BUILD.gn | 15 +++++ handler/handler_main.cc | 12 ++++ handler/linux/handler_trampoline.cc | 45 ++++++++++++++ 5 files changed, 248 insertions(+) create mode 100644 handler/linux/handler_trampoline.cc diff --git a/client/crashpad_client.h b/client/crashpad_client.h index ea0e7b6d..8bf43acd 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -188,6 +188,97 @@ class CrashpadClient { const std::map<std::string, std::string>& annotations, const std::vector<std::string>& arguments, int socket); + + //! \brief Installs a signal handler to start a Crashpad handler process by + //! loading it with `/system/bin/linker`. + //! + //! This method is only supported by Android Q+. + //! + //! \param[in] handler_trampoline The path to a Crashpad handler trampoline + //! executable, possibly located within an apk, e.g. + //! "/data/app/myapk.apk!/myabi/libcrashpad_handler_trampoline.so". + //! \param[in] handler_library The name of a library exporting the symbol + //! `CrashpadHandlerMain()`. The path to this library must be present in + //! `LD_LIBRARY_PATH`. + //! \param[in] is_64_bit `true` if \a handler_trampoline and \a + //! handler_library are 64-bit objects. They must have the same bitness. + //! \param[in] env A vector of environment variables of the form `var=value` + //! defining the environment in which to execute `app_process`. If this + //! value is `nullptr`, the application's environment at the time of the + //! crash will be used. + //! \param[in] database The path to a Crashpad database. The handler will be + //! started with this path as its `--database` argument. + //! \param[in] metrics_dir The path to an already existing directory where + //! metrics files can be stored. The handler will be started with this + //! path as its `--metrics-dir` argument. + //! \param[in] url The URL of an upload server. The handler will be started + //! with this URL as its `--url` argument. + //! \param[in] annotations Process annotations to set in each crash report. + //! The handler will be started with an `--annotation` argument for each + //! element in this map. + //! \param[in] arguments Additional arguments to pass to the Crashpad handler. + //! Arguments passed in other parameters and arguments required to perform + //! the handshake are the responsibility of this method, and must not be + //! specified in this parameter. + //! + //! \return `true` on success, `false` on failure with a message logged. + static bool StartHandlerWithLinkerAtCrash( + const std::string& handler_trampoline, + const std::string& handler_library, + bool is_64_bit, + const std::vector<std::string>* env, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments); + + //! \brief Starts a Crashpad handler process with an initial client by loading + //! it with `/system/bin/linker`. + //! + //! This method is only supported by Android Q+. + //! + //! \param[in] handler_trampoline The path to a Crashpad handler trampoline + //! executable, possibly located within an apk, e.g. + //! "/data/app/myapk.apk!/myabi/libcrashpad_handler_trampoline.so". + //! \param[in] handler_library The name of a library exporting the symbol + //! `CrashpadHandlerMain()`. The path to this library must be present in + //! `LD_LIBRARY_PATH`. + //! \param[in] is_64_bit `true` if \a handler_trampoline and \a + //! handler_library are 64-bit objects. They must have the same bitness. + //! \param[in] env A vector of environment variables of the form `var=value` + //! defining the environment in which to execute `app_process`. If this + //! value is `nullptr`, the application's current environment will be + //! used. + //! \param[in] database The path to a Crashpad database. The handler will be + //! started with this path as its `--database` argument. + //! \param[in] metrics_dir The path to an already existing directory where + //! metrics files can be stored. The handler will be started with this + //! path as its `--metrics-dir` argument. + //! \param[in] url The URL of an upload server. The handler will be started + //! with this URL as its `--url` argument. + //! \param[in] annotations Process annotations to set in each crash report. + //! The handler will be started with an `--annotation` argument for each + //! element in this map. + //! \param[in] arguments Additional arguments to pass to the Crashpad handler. + //! Arguments passed in other parameters and arguments required to perform + //! the handshake are the responsibility of this method, and must not be + //! specified in this parameter. + //! \param[in] socket The server end of a socket pair. The client end should + //! be used with an ExceptionHandlerClient. + //! + //! \return `true` on success, `false` on failure with a message logged. + static bool StartHandlerWithLinkerForClient( + const std::string& handler_trampoline, + const std::string& handler_library, + bool is_64_bit, + const std::vector<std::string>* env, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments, + int socket); #endif // OS_ANDROID || DOXYGEN #if defined(OS_LINUX) || defined(OS_ANDROID) || DOXYGEN diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 556a91fc..fe5798a5 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -77,6 +77,36 @@ std::vector<std::string> BuildAppProcessArgs( return argv; } +std::vector<std::string> BuildArgsToLaunchWithLinker( + const std::string& handler_trampoline, + const std::string& handler_library, + bool is_64_bit, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments, + int socket) { + std::vector<std::string> argv; + if (is_64_bit) { + argv.push_back("/system/bin/linker64"); + } else { + argv.push_back("/system/bin/linker"); + } + argv.push_back(handler_trampoline); + argv.push_back(handler_library); + + std::vector<std::string> handler_argv = BuildHandlerArgvStrings( + base::FilePath(), database, metrics_dir, url, annotations, arguments); + + if (socket != kInvalidFileHandle) { + handler_argv.push_back(FormatArgumentInt("initial-client-fd", socket)); + } + + argv.insert(argv.end(), handler_argv.begin() + 1, handler_argv.end()); + return argv; +} + #endif // OS_ANDROID // Launches a single use handler to snapshot this process. @@ -251,6 +281,61 @@ bool CrashpadClient::StartJavaHandlerForClient( return DoubleForkAndExec(argv, env, socket, false, nullptr); } +// static +bool CrashpadClient::StartHandlerWithLinkerAtCrash( + const std::string& handler_trampoline, + const std::string& handler_library, + bool is_64_bit, + const std::vector<std::string>* env, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments) { + std::vector<std::string> argv = + BuildArgsToLaunchWithLinker(handler_trampoline, + handler_library, + is_64_bit, + database, + metrics_dir, + url, + annotations, + arguments, + kInvalidFileHandle); + auto signal_handler = LaunchAtCrashHandler::Get(); + if (signal_handler->Initialize(&argv, env)) { + DCHECK(!g_crash_handler); + g_crash_handler = signal_handler; + return true; + } + return false; +} + +// static +bool CrashpadClient::StartHandlerWithLinkerForClient( + const std::string& handler_trampoline, + const std::string& handler_library, + bool is_64_bit, + const std::vector<std::string>* env, + const base::FilePath& database, + const base::FilePath& metrics_dir, + const std::string& url, + const std::map<std::string, std::string>& annotations, + const std::vector<std::string>& arguments, + int socket) { + std::vector<std::string> argv = + BuildArgsToLaunchWithLinker(handler_trampoline, + handler_library, + is_64_bit, + database, + metrics_dir, + url, + annotations, + arguments, + socket); + return DoubleForkAndExec(argv, env, socket, false, nullptr); +} + #endif // static diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 32d4d6c1..bbd68ab1 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -166,6 +166,21 @@ if (crashpad_is_android) { "$root_out_dir/libcrashpad_handler.so", ] } + + crashpad_executable("crashpad_handler_trampoline") { + set_sources_assignment_filter([]) + output_name = "libcrashpad_handler_trampoline.so" + + sources = [ + "linux/handler_trampoline.cc", + ] + + ldflags = [ "-llog" ] + + if (crashpad_is_in_chromium) { + no_default_deps = true + } + } } crashpad_executable("crashpad_handler_test_extended_handler") { diff --git a/handler/handler_main.cc b/handler/handler_main.cc index b3e0a68a..31686b3e 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -497,6 +497,18 @@ class ScopedStoppable { } // namespace +#if defined(OS_ANDROID) + +extern "C" { +__attribute__((visibility("default"), used)) int CrashpadHandlerMain( + int argc, + char* argv[]) { + return HandlerMain(argc, argv, nullptr); +} +} // extern "C" + +#endif // OS_ANDROID + int HandlerMain(int argc, char* argv[], const UserStreamDataSources* user_stream_sources) { diff --git a/handler/linux/handler_trampoline.cc b/handler/linux/handler_trampoline.cc new file mode 100644 index 00000000..34535631 --- /dev/null +++ b/handler/linux/handler_trampoline.cc @@ -0,0 +1,45 @@ +// 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. + +#include <android/log.h> +#include <dlfcn.h> +#include <stdlib.h> + +// The first argument passed to the trampoline is the name of the native library +// exporting the symbol `CrashpadHandlerMain`. The remaining arguments are the +// same as for `HandlerMain()`. +int main(int argc, char* argv[]) { + static constexpr char kTag[] = "crashpad"; + + if (argc < 2) { + __android_log_print(ANDROID_LOG_FATAL, kTag, "usage: %s <path>", argv[0]); + return EXIT_FAILURE; + } + + void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL); + if (!handle) { + __android_log_print(ANDROID_LOG_FATAL, kTag, "dlopen: %s", dlerror()); + return EXIT_FAILURE; + } + + using MainType = int (*)(int, char*[]); + MainType crashpad_main = + reinterpret_cast<MainType>(dlsym(handle, "CrashpadHandlerMain")); + if (!crashpad_main) { + __android_log_print(ANDROID_LOG_FATAL, kTag, "dlsym: %s", dlerror()); + return EXIT_FAILURE; + } + + return crashpad_main(argc - 1, argv + 1); +} From 48ee086ca4c4cda9c2e8606a8775ae6cb80ad400 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 21 Feb 2019 12:06:55 -0800 Subject: [PATCH 146/401] fuchsia: Update to run crashpad_test as package rather than from /system In the Fuchsia tree, tests can now be run via `fx run-test crashpad_test`. Bug: crashpad:196 Change-Id: I427cde7090b00b46c9d6a948664701f98b014e9d Reviewed-on: https://chromium-review.googlesource.com/c/1481811 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Francois Rousseau <frousseau@google.com> --- BUILD.gn | 48 +++++++++++---------------------- test/fuchsia_crashpad_tests.cmx | 21 +++++++++++++++ test/test_paths.cc | 31 +++------------------ 3 files changed, 40 insertions(+), 60 deletions(-) create mode 100644 test/fuchsia_crashpad_tests.cmx diff --git a/BUILD.gn b/BUILD.gn index ce9edf75..f474a2c7 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -37,7 +37,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { import("//build/package.gni") package("crashpad_test") { testonly = true - deprecated_system_image = true deps = [ ":crashpad_tests", @@ -55,19 +54,21 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { }, ] - # Note that the infix of "crashpad_tests" below in - # binary/resource entries should be removed once - # crashpad_tests is moved out of the system image; - # until then, it is used to disambiguate the crashpad - # binaries and data from others within /system/(bin|data). + meta = [ + { + path = "test/fuchsia_crashpad_tests.cmx" + dest = "crashpad_tests.cmx" + } + ] + binaries = [ { name = "crashpad_test_test_multiprocess_exec_test_child" - dest = "crashpad_tests/crashpad_test_test_multiprocess_exec_test_child" + dest = "crashpad_test_test_multiprocess_exec_test_child" }, { name = "http_transport_test_server" - dest = "crashpad_tests/http_transport_test_server" + dest = "http_transport_test_server" }, ] @@ -89,52 +90,34 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { resources = [ { path = "util/net/testdata/ascii_http_body.txt" - dest = "crashpad_tests/util/net/testdata/ascii_http_body.txt" + dest = "util/net/testdata/ascii_http_body.txt" }, { path = "util/net/testdata/binary_http_body.dat" - dest = "crashpad_tests/util/net/testdata/binary_http_body.dat" + dest = "util/net/testdata/binary_http_body.dat" }, { path = "test/test_paths_test_data_root.txt" - dest = "crashpad_tests/test/test_paths_test_data_root.txt" + dest = "test/test_paths_test_data_root.txt" }, ] if (crashpad_use_boringssl_for_http_transport_socket) { - deps += [ - "util:generate_test_server_key", - ] + deps += [ "util:generate_test_server_key" ] resources += [ { path = "$root_out_dir/crashpad_util_test_cert.pem" - dest = "crashpad_tests/crashpad_util_test_cert.pem" + dest = "crashpad_util_test_cert.pem" }, { path = "$root_out_dir/crashpad_util_test_key.pem" - dest = "crashpad_tests/crashpad_util_test_key.pem" + dest = "crashpad_util_test_key.pem" }, ] } } - package("crashpad_handler") { - deprecated_system_image = true - - deps = [ - "handler:crashpad_handler", - ] - - binaries = [ - { - name = "crashpad_handler" - }, - ] - } - package("crashpad_database_util") { - deprecated_system_image = true - deps = [ "tools:crashpad_database_util", ] @@ -142,6 +125,7 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { binaries = [ { name = "crashpad_database_util" + shell = true }, ] } diff --git a/test/fuchsia_crashpad_tests.cmx b/test/fuchsia_crashpad_tests.cmx new file mode 100644 index 00000000..6b666379 --- /dev/null +++ b/test/fuchsia_crashpad_tests.cmx @@ -0,0 +1,21 @@ +{ + "facets": { + "fuchsia.test": { + "system-services": [ + "fuchsia.net.SocketProvider" + ] + } + }, + "program": { + "binary": "test/crashpad_tests" + }, + "sandbox": { + "features": [ + "system-temp" + ], + "services": [ + "fuchsia.net.SocketProvider", + "fuchsia.process.Launcher" + ] + } +} diff --git a/test/test_paths.cc b/test/test_paths.cc index 3b611b12..10bae7a2 100644 --- a/test/test_paths.cc +++ b/test/test_paths.cc @@ -44,14 +44,7 @@ bool IsTestDataRoot(const base::FilePath& candidate) { base::FilePath TestDataRootInternal() { #if defined(OS_FUCHSIA) - base::FilePath asset_path("/pkg/assets"); -#if defined(CRASHPAD_IS_IN_FUCHSIA) - // Tests are not yet packaged when running in the Fuchsia tree, so assets do - // not appear as expected at /pkg/assets. Override the default so that tests - // can find their data for now. - // https://crashpad.chromium.org/bug/196. - asset_path = base::FilePath("/system/data/crashpad_tests"); -#endif + base::FilePath asset_path("/pkg/data"); if (!IsTestDataRoot(asset_path)) { LOG(WARNING) << "Test data root seems invalid, continuing anyway"; } @@ -129,11 +122,7 @@ base::FilePath TestPaths::Executable() { base::FilePath executable_path; CHECK(Paths::Executable(&executable_path)); #if defined(CRASHPAD_IS_IN_FUCHSIA) - // Tests are not yet packaged when running in the Fuchsia tree, so binaries do - // not appear as expected at /pkg/bin. Override the default of /pkg/bin/app - // so that tests can find the correct location for now. - // https://crashpad.chromium.org/bug/196. - executable_path = base::FilePath("/system/bin/crashpad_tests/app"); + executable_path = base::FilePath("/pkg/bin/app"); #endif return executable_path; } @@ -202,16 +191,7 @@ base::FilePath TestPaths::BuildArtifact( #if defined(OS_WIN) extension = FILE_PATH_LITERAL(".exe"); #elif defined(OS_FUCHSIA) -#if defined(CRASHPAD_IS_IN_FUCHSIA) - // Tests are not yet packaged when running in the Fuchsia tree, so - // binaries do not appear as expected at /pkg/bin. Override the default of - // /pkg/bin/app so that tests can find the correct location for now. - // https://crashpad.chromium.org/bug/196. - directory = - base::FilePath(FILE_PATH_LITERAL("/system/bin/crashpad_tests")); -#else directory = base::FilePath(FILE_PATH_LITERAL("/pkg/bin")); -#endif #endif // OS_WIN break; @@ -233,12 +213,7 @@ base::FilePath TestPaths::BuildArtifact( case FileType::kCertificate: #if defined(CRASHPAD_IS_IN_FUCHSIA) - // When running in the Fuchsia tree, the .pem files are packaged as assets - // into the test data folder. This will need to be rationalized when - // things are actually run from a package. - // https://crashpad.chromium.org/bug/196. - directory = - base::FilePath(FILE_PATH_LITERAL("/system/data/crashpad_tests")); + directory = base::FilePath(FILE_PATH_LITERAL("/pkg/data")); #endif extension = FILE_PATH_LITERAL(".pem"); break; From 2271f00fe0760f0d6abcf2df64ac299382d2148d Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 26 Feb 2019 11:13:20 -0500 Subject: [PATCH 147/401] Add missing BUILD.gn for third_party/apple_cf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apple_cf is just a header, but we’ve got a BUILD.gn for third_party/cpp-httplib, which is also just a header. Change-Id: Ib42c25657b5964678d14682a0a802ebef0e4cb2f Reviewed-on: https://chromium-review.googlesource.com/c/1489182 Reviewed-by: Robert Sesek <rsesek@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- third_party/apple_cf/BUILD.gn | 19 +++++++++++++++++++ util/BUILD.gn | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 third_party/apple_cf/BUILD.gn diff --git a/third_party/apple_cf/BUILD.gn b/third_party/apple_cf/BUILD.gn new file mode 100644 index 00000000..43c62eb2 --- /dev/null +++ b/third_party/apple_cf/BUILD.gn @@ -0,0 +1,19 @@ +# 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("apple_cf") { + sources = [ + "CFStreamAbstract.h", + ] +} diff --git a/util/BUILD.gn b/util/BUILD.gn index b5e1561a..41a74d63 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -441,7 +441,10 @@ static_library("util") { "Foundation.framework", "IOKit.framework", ] - deps += [ ":mig" ] + deps += [ + ":mig", + "../third_party/apple_cf:apple_cf", + ] include_dirs += [ "$root_build_dir/gen" ] } From 3332ae35467233df14a2c66e2dcac81cddd189d3 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 26 Feb 2019 16:59:46 -0500 Subject: [PATCH 148/401] compat: Provide <elf.h> and <mach-o/loader.h> for everyone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I’m working on something that I’m not ready to share, but maintaining these compat headers in my local branch is becoming annoying because “git cl format” keeps reformatting them since they were added since my local branch point. Because these headers are non-trivial, they’re brought nearly unmodified from upstream into third_party, with forwarding from the appropriate locations in compat. <elf.h> comes from glibc 2.29 (2019-01-31) and was modified to remove the #include of <features.h> and to replace the use of __BEGIN_DECLS and __END_DECLS with the proper conditional extern "C" construct. <mach-o/loader.h> comes from xnu 4903.221.2 (macOS 10.14.1, 2018-10-30) and was modified to remove the unused #includes of <mach/machine/thread_status.h> and <architecture/byte_order.h>. Rather than taking <mach/machine.h> and <mach/vm_prot.h> with a spider web of other dependencies from xnu, compat has cut-back versions of these headers that provide only the required typedefs. This also includes an update of apple_cf to 1153.18 (OS X 10.10.3, 2015-04-08), the last public release of CF-Lite. The change doesn’t do much for our purposes, but it restores the file to an Apple-shipped state, trailing whitespace and all. This also canonically formats BUILD.gn. 48ee086ca4c4c didn’t format it. Change-Id: Ib4f28ad53d9757bd0eed838e148c51172bfe30b1 Reviewed-on: https://chromium-review.googlesource.com/c/1489795 Reviewed-by: Robert Sesek <rsesek@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- BUILD.gn | 2 +- compat/BUILD.gn | 25 +- compat/non_elf/elf.h | 20 + compat/non_mac/mach-o/loader.h | 20 + compat/non_mac/mach/machine.h | 21 + compat/non_mac/mach/vm_prot.h | 20 + third_party/apple_cf/CFStreamAbstract.h | 17 +- third_party/apple_cf/README.crashpad | 2 +- third_party/glibc/BUILD.gn | 19 + third_party/glibc/COPYING.LIB | 502 +++ third_party/glibc/README.crashpad | 16 + third_party/glibc/elf/elf.h | 4003 +++++++++++++++++ third_party/xnu/APPLE_LICENSE | 367 ++ third_party/xnu/BUILD.gn | 19 + .../xnu/EXTERNAL_HEADERS/mach-o/loader.h | 1531 +++++++ third_party/xnu/README.crashpad | 19 + 16 files changed, 6595 insertions(+), 8 deletions(-) create mode 100644 compat/non_elf/elf.h create mode 100644 compat/non_mac/mach-o/loader.h create mode 100644 compat/non_mac/mach/machine.h create mode 100644 compat/non_mac/mach/vm_prot.h create mode 100644 third_party/glibc/BUILD.gn create mode 100644 third_party/glibc/COPYING.LIB create mode 100644 third_party/glibc/README.crashpad create mode 100644 third_party/glibc/elf/elf.h create mode 100644 third_party/xnu/APPLE_LICENSE create mode 100644 third_party/xnu/BUILD.gn create mode 100644 third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h create mode 100644 third_party/xnu/README.crashpad diff --git a/BUILD.gn b/BUILD.gn index f474a2c7..10850c6c 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -58,7 +58,7 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { { path = "test/fuchsia_crashpad_tests.cmx" dest = "crashpad_tests.cmx" - } + }, ] binaries = [ diff --git a/compat/BUILD.gn b/compat/BUILD.gn index 9f247a45..7a33d7ca 100644 --- a/compat/BUILD.gn +++ b/compat/BUILD.gn @@ -19,6 +19,8 @@ config("compat_config") { if (crashpad_is_mac) { include_dirs += [ "mac" ] + } else { + include_dirs += [ "non_mac" ] } if (crashpad_is_linux || crashpad_is_android) { @@ -34,6 +36,10 @@ config("compat_config") { } else { include_dirs += [ "non_win" ] } + + if (!crashpad_is_linux && !crashpad_is_android && !crashpad_is_fuchsia) { + include_dirs += [ "non_elf" ] + } } template("compat_target") { @@ -62,7 +68,12 @@ compat_target("compat") { "mac/sys/resource.h", ] } else { - sources += [ "non_mac/mach/mach.h" ] + sources += [ + "non_mac/mach-o/loader.h", + "non_mac/mach/mach.h", + "non_mac/mach/machine.h", + "non_mac/mach/vm_prot.h", + ] } if (crashpad_is_linux || crashpad_is_android) { @@ -116,6 +127,10 @@ compat_target("compat") { ] } + if (!crashpad_is_linux && !crashpad_is_android && !crashpad_is_fuchsia) { + sources += [ "non_elf/elf.h" ] + } + public_configs = [ ":compat_config", "..:crashpad_config", @@ -123,7 +138,15 @@ compat_target("compat") { deps = [] + if (!crashpad_is_mac) { + deps += [ "../third_party/xnu" ] + } + if (crashpad_is_win) { deps += [ "../third_party/getopt" ] } + + if (!crashpad_is_linux && !crashpad_is_android && !crashpad_is_fuchsia) { + deps += [ "../third_party/glibc" ] + } } diff --git a/compat/non_elf/elf.h b/compat/non_elf/elf.h new file mode 100644 index 00000000..1245f16d --- /dev/null +++ b/compat/non_elf/elf.h @@ -0,0 +1,20 @@ +// 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/compat/non_mac/mach-o/loader.h b/compat/non_mac/mach-o/loader.h new file mode 100644 index 00000000..98a8b5fa --- /dev/null +++ b/compat/non_mac/mach-o/loader.h @@ -0,0 +1,20 @@ +// 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_MAC_MACH_O_LOADER_H_ +#define CRASHPAD_COMPAT_NON_MAC_MACH_O_LOADER_H_ + +#include "third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h" + +#endif // CRASHPAD_COMPAT_NON_MAC_MACH_O_LOADER_H_ diff --git a/compat/non_mac/mach/machine.h b/compat/non_mac/mach/machine.h new file mode 100644 index 00000000..54d4742b --- /dev/null +++ b/compat/non_mac/mach/machine.h @@ -0,0 +1,21 @@ +// 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_MAC_MACH_MACHINE_H_ +#define CRASHPAD_COMPAT_NON_MAC_MACH_MACHINE_H_ + +typedef int cpu_type_t; +typedef int cpu_subtype_t; + +#endif // CRASHPAD_COMPAT_NON_MAC_MACH_MACHINE_H_ diff --git a/compat/non_mac/mach/vm_prot.h b/compat/non_mac/mach/vm_prot.h new file mode 100644 index 00000000..12001791 --- /dev/null +++ b/compat/non_mac/mach/vm_prot.h @@ -0,0 +1,20 @@ +// 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_MAC_MACH_VM_PROT_H_ +#define CRASHPAD_COMPAT_NON_MAC_MACH_VM_PROT_H_ + +typedef int vm_prot_t; + +#endif // CRASHPAD_COMPAT_NON_MAC_MACH_VM_PROT_H_ diff --git a/third_party/apple_cf/CFStreamAbstract.h b/third_party/apple_cf/CFStreamAbstract.h index bf12c928..ac26664f 100644 --- a/third_party/apple_cf/CFStreamAbstract.h +++ b/third_party/apple_cf/CFStreamAbstract.h @@ -1,15 +1,15 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2015 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,12 +17,12 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ /* CFStreamAbstract.h - Copyright (c) 2000-2009, Apple Inc. All rights reserved. + Copyright (c) 2000-2014, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTREAMABSTRACT__) @@ -134,11 +134,18 @@ CF_EXPORT void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream); // Returns an array of the runloops and modes on which the stream is currently scheduled +// Note that these are unretained mutable arrays - use the copy variant instead. CF_EXPORT CFArrayRef _CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream); CF_EXPORT CFArrayRef _CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream); +// Returns an array of the runloops and modes on which the stream is currently scheduled +CF_EXPORT +CFArrayRef _CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream); +CF_EXPORT +CFArrayRef _CFWriteStreamCopyRunLoopsAndModes(CFWriteStreamRef writeStream); + /* Deprecated versions; here for backwards compatibility. */ typedef struct { CFIndex version; /* == 1 */ diff --git a/third_party/apple_cf/README.crashpad b/third_party/apple_cf/README.crashpad index b6c6cfad..20066484 100644 --- a/third_party/apple_cf/README.crashpad +++ b/third_party/apple_cf/README.crashpad @@ -2,7 +2,7 @@ Name: Apple CF-Lite Short Name: CF URL: https://opensource.apple.com/source/CF/ URL: https://opensource.apple.com/tarballs/CF/ -Version: 550.43 (from Mac OS X 10.6.8) +Version: 1153.18 (from OS X 10.10.3) License: APSL 2.0 License File: APPLE_LICENSE Security Critical: no diff --git a/third_party/glibc/BUILD.gn b/third_party/glibc/BUILD.gn new file mode 100644 index 00000000..e12febfe --- /dev/null +++ b/third_party/glibc/BUILD.gn @@ -0,0 +1,19 @@ +# 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 new file mode 100644 index 00000000..4362b491 --- /dev/null +++ b/third_party/glibc/COPYING.LIB @@ -0,0 +1,502 @@ + 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. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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. + + <signature of Ty Coon>, 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 new file mode 100644 index 00000000..b550ad98 --- /dev/null +++ b/third_party/glibc/README.crashpad @@ -0,0 +1,16 @@ +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 <features.h> 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 new file mode 100644 index 00000000..331536b4 --- /dev/null +++ b/third_party/glibc/elf/elf.h @@ -0,0 +1,4003 @@ +/* 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 + <http://www.gnu.org/licenses/>. */ + +#ifndef _ELF_H +#define _ELF_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Standard ELF types. */ + +#include <stdint.h> + +/* 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 <elf.h> 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<cond>). */ +#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<cond>.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<cond>). */ +#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 */ diff --git a/third_party/xnu/APPLE_LICENSE b/third_party/xnu/APPLE_LICENSE new file mode 100644 index 00000000..fe81a60c --- /dev/null +++ b/third_party/xnu/APPLE_LICENSE @@ -0,0 +1,367 @@ +APPLE PUBLIC SOURCE LICENSE +Version 2.0 - August 6, 2003 + +Please read this License carefully before downloading this software. +By downloading or using this software, you are agreeing to be bound by +the terms of this License. If you do not or cannot agree to the terms +of this License, please do not download or use the software. + +1. General; Definitions. This License applies to any program or other +work which Apple Computer, Inc. ("Apple") makes publicly available and +which contains a notice placed by Apple identifying such program or +work as "Original Code" and stating that it is subject to the terms of +this Apple Public Source License version 2.0 ("License"). As used in +this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is +the grantor of rights, (i) claims of patents that are now or hereafter +acquired, owned by or assigned to Apple and (ii) that cover subject +matter contained in the Original Code, but only to the extent +necessary to use, reproduce and/or distribute the Original Code +without infringement; and (b) in the case where You are the grantor of +rights, (i) claims of patents that are now or hereafter acquired, +owned by or assigned to You and (ii) that cover subject matter in Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Contributor" means any person or entity that creates or +contributes to the creation of Modifications. + +1.3 "Covered Code" means the Original Code, Modifications, the +combination of Original Code and any Modifications, and/or any +respective portions thereof. + +1.4 "Externally Deploy" means: (a) to sublicense, distribute or +otherwise make Covered Code available, directly or indirectly, to +anyone other than You; and/or (b) to use Covered Code, alone or as +part of a Larger Work, in any way to provide a service, including but +not limited to delivery of content, through electronic communication +with a client other than You. + +1.5 "Larger Work" means a work which combines Covered Code or portions +thereof with code not governed by the terms of this License. + +1.6 "Modifications" mean any addition to, deletion from, and/or change +to, the substance and/or structure of the Original Code, any previous +Modifications, the combination of Original Code and any previous +Modifications, and/or any respective portions thereof. When code is +released as a series of files, a Modification is: (a) any addition to +or deletion from the contents of a file containing Covered Code; +and/or (b) any new file or other representation of computer program +statements that contains any part of Covered Code. + +1.7 "Original Code" means (a) the Source Code of a program or other +work as originally made available by Apple under this License, +including the Source Code of any updates or upgrades to such programs +or works made available by Apple under this License, and that has been +expressly identified by Apple as such in the header file(s) of such +work; and (b) the object code compiled from such Source Code and +originally made available by Apple under this License. + +1.8 "Source Code" means the human readable form of a program or other +work that is suitable for making modifications to it, including all +modules it contains, plus any associated interface definition files, +scripts used to control compilation and installation of an executable +(object code). + +1.9 "You" or "Your" means an individual or a legal entity exercising +rights under this License. For legal entities, "You" or "Your" +includes any entity which controls, is controlled by, or is under +common control with, You, where "control" means (a) the power, direct +or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (b) ownership of fifty percent +(50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms +and conditions of this License, Apple hereby grants You, effective on +the date You accept this License and download the Original Code, a +world-wide, royalty-free, non-exclusive license, to the extent of +Apple's Applicable Patent Rights and copyrights covering the Original +Code, to do the following: + +2.1 Unmodified Code. You may use, reproduce, display, perform, +internally distribute within Your organization, and Externally Deploy +verbatim, unmodified copies of the Original Code, for commercial or +non-commercial purposes, provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the +copyright and other proprietary notices and disclaimers of Apple as +they appear in the Original Code, and keep intact all notices in the +Original Code that refer to this License; and + +(b) You must include a copy of this License with every copy of Source +Code of Covered Code and documentation You distribute or Externally +Deploy, and You may not offer or impose any terms on such Source Code +that alter or restrict this License or the recipients' rights +hereunder, except as permitted under Section 6. + +2.2 Modified Code. You may modify Covered Code and use, reproduce, +display, perform, internally distribute within Your organization, and +Externally Deploy Your Modifications and Covered Code, for commercial +or non-commercial purposes, provided that in each instance You also +meet all of these conditions: + +(a) You must satisfy all the conditions of Section 2.1 with respect to +the Source Code of the Covered Code; + +(b) You must duplicate, to the extent it does not already exist, the +notice in Exhibit A in each file of the Source Code of all Your +Modifications, and cause the modified files to carry prominent notices +stating that You changed the files and the date of any change; and + +(c) If You Externally Deploy Your Modifications, You must make +Source Code of all Your Externally Deployed Modifications either +available to those to whom You have Externally Deployed Your +Modifications, or publicly available. Source Code of Your Externally +Deployed Modifications must be released under the terms set forth in +this License, including the license grants set forth in Section 3 +below, for as long as you Externally Deploy the Covered Code or twelve +(12) months from the date of initial External Deployment, whichever is +longer. You should preferably distribute the Source Code of Your +Externally Deployed Modifications electronically (e.g. download from a +web site). + +2.3 Distribution of Executable Versions. In addition, if You +Externally Deploy Covered Code (Original Code and/or Modifications) in +object code, executable form only, You must include a prominent +notice, in the code itself as well as in related documentation, +stating that Source Code of the Covered Code is available under the +terms of this License with information on how and where to obtain such +Source Code. + +2.4 Third Party Rights. You expressly acknowledge and agree that +although Apple and each Contributor grants the licenses to their +respective portions of the Covered Code set forth herein, no +assurances are provided by Apple or any Contributor that the Covered +Code does not infringe the patent or other intellectual property +rights of any other entity. Apple and each Contributor disclaim any +liability to You for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a +condition to exercising the rights and licenses granted hereunder, You +hereby assume sole responsibility to secure any other intellectual +property rights needed, if any. For example, if a third party patent +license is required to allow You to distribute the Covered Code, it is +Your responsibility to acquire that license before distributing the +Covered Code. + +3. Your Grants. In consideration of, and as a condition to, the +licenses granted to You under this License, You hereby grant to any +person or entity receiving or distributing Covered Code under this +License a non-exclusive, royalty-free, perpetual, irrevocable license, +under Your Applicable Patent Rights and other intellectual property +rights (other than patent) owned or controlled by You, to use, +reproduce, display, perform, modify, sublicense, distribute and +Externally Deploy Your Modifications of the same scope and extent as +Apple's licenses under Sections 2.1 and 2.2 above. + +4. Larger Works. You may create a Larger Work by combining Covered +Code with other code not governed by the terms of this License and +distribute the Larger Work as a single product. In each such instance, +You must make sure the requirements of this License are fulfilled for +the Covered Code or any portion thereof. + +5. Limitations on Patent License. Except as expressly stated in +Section 2, no other patent rights, express or implied, are granted by +Apple herein. Modifications and/or Larger Works may require additional +patent licenses from Apple which Apple may grant in its sole +discretion. + +6. Additional Terms. You may choose to offer, and to charge a fee for, +warranty, support, indemnity or liability obligations and/or other +rights consistent with the scope of the license granted herein +("Additional Terms") to one or more recipients of Covered Code. +However, You may do so only on Your own behalf and as Your sole +responsibility, and not on behalf of Apple or any Contributor. You +must obtain the recipient's agreement that any such Additional Terms +are offered by You alone, and You hereby agree to indemnify, defend +and hold Apple and every Contributor harmless for any liability +incurred by or claims asserted against Apple or such Contributor by +reason of any such Additional Terms. + +7. Versions of the License. Apple may publish revised and/or new +versions of this License from time to time. Each version will be given +a distinguishing version number. Once Original Code has been published +under a particular version of this License, You may continue to use it +under the terms of that version. You may also choose to use such +Original Code under the terms of any subsequent version of this +License published by Apple. No one other than Apple has the right to +modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in +part pre-release, untested, or not fully tested works. The Covered +Code may contain errors that could cause failures or loss of data, and +may be incomplete or contain inaccuracies. You expressly acknowledge +and agree that use of the Covered Code, or any portion thereof, is at +Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND +WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND +APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE +PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM +ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF +MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR +PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD +PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST +INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE +FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS, +THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO +ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. +You acknowledge that the Covered Code is not intended for use in the +operation of nuclear facilities, aircraft navigation, communication +systems, or air traffic control machines in which case the failure of +the Covered Code could lead to death, personal injury, or severe +physical or environmental damage. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO +EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING +TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR +ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY, +TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF +APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY +REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF +INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY +TO YOU. In no event shall Apple's total liability to You for all +damages (other than as may be required by applicable law) under this +License exceed the amount of fifty dollars ($50.00). + +10. Trademarks. This License does not grant any rights to use the +trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS", +"QuickTime", "QuickTime Streaming Server" or any other trademarks, +service marks, logos or trade names belonging to Apple (collectively +"Apple Marks") or to any trademark, service mark, logo or trade name +belonging to any Contributor. You agree not to use any Apple Marks in +or as part of the name of products derived from the Original Code or +to endorse or promote products derived from the Original Code other +than as expressly permitted by and in strict compliance at all times +with Apple's third party trademark usage guidelines which are posted +at http://www.apple.com/legal/guidelinesfor3rdparties.html. + +11. Ownership. Subject to the licenses granted under this License, +each Contributor retains all rights, title and interest in and to any +Modifications made by such Contributor. Apple retains all rights, +title and interest in and to the Original Code and any Modifications +made by or on behalf of Apple ("Apple Modifications"), and such Apple +Modifications will not be automatically subject to this License. Apple +may, at its sole discretion, choose to license such Apple +Modifications under this License, or on different terms from those +contained in this License or may choose not to license them at all. + +12. Termination. + +12.1 Termination. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Apple if You fail to comply with +any term(s) of this License and fail to cure such breach within 30 +days of becoming aware of such breach; + +(b) immediately in the event of the circumstances described in Section +13.5(b); or + +(c) automatically without notice from Apple if You, at any time during +the term of this License, commence an action for patent infringement +against Apple; provided that Apple did not first commence +an action for patent infringement against You in that instance. + +12.2 Effect of Termination. Upon termination, You agree to immediately +stop any further use, reproduction, modification, sublicensing and +distribution of the Covered Code. All sublicenses to the Covered Code +which have been properly granted prior to termination shall survive +any termination of this License. Provisions which, by their nature, +should remain in effect beyond the termination of this License shall +survive, including but not limited to Sections 3, 5, 8, 9, 10, 11, +12.2 and 13. No party will be liable to any other for compensation, +indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this +License will be without prejudice to any other right or remedy of +any party. + +13. Miscellaneous. + +13.1 Government End Users. The Covered Code is a "commercial item" as +defined in FAR 2.101. Government software and technical data rights in +the Covered Code include only those rights customarily provided to the +public as defined in this License. This customary commercial license +in technical data and software is provided in accordance with FAR +12.211 (Technical Data) and 12.212 (Computer Software) and, for +Department of Defense purchases, DFAR 252.227-7015 (Technical Data -- +Commercial Items) and 227.7202-3 (Rights in Commercial Computer +Software or Computer Software Documentation). Accordingly, all U.S. +Government End Users acquire Covered Code with only those rights set +forth herein. + +13.2 Relationship of Parties. This License will not be construed as +creating an agency, partnership, joint venture or any other form of +legal association between or among You, Apple or any Contributor, and +You will not represent to the contrary, whether expressly, by +implication, appearance or otherwise. + +13.3 Independent Development. Nothing in this License will impair +Apple's right to acquire, license, develop, have others develop for +it, market and/or distribute technology or products that perform the +same or similar functions as, or otherwise compete with, +Modifications, Larger Works, technology or products that You may +develop, produce, market or distribute. + +13.4 Waiver; Construction. Failure by Apple or any Contributor to +enforce any provision of this License will not be deemed a waiver of +future enforcement of that or any other provision. Any law or +regulation which provides that the language of a contract shall be +construed against the drafter will not apply to this License. + +13.5 Severability. (a) If for any reason a court of competent +jurisdiction finds any provision of this License, or portion thereof, +to be unenforceable, that provision of the License will be enforced to +the maximum extent permissible so as to effect the economic benefits +and intent of the parties, and the remainder of this License will +continue in full force and effect. (b) Notwithstanding the foregoing, +if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the +enforceability of either of those Sections, this License will +immediately terminate and You must immediately discontinue any use of +the Covered Code and destroy all copies of it that are in your +possession or control. + +13.6 Dispute Resolution. Any litigation or other dispute resolution +between You and Apple relating to this License shall take place in the +Northern District of California, and You and Apple hereby consent to +the personal jurisdiction of, and venue in, the state and federal +courts within that District with respect to this License. The +application of the United Nations Convention on Contracts for the +International Sale of Goods is expressly excluded. + +13.7 Entire Agreement; Governing Law. This License constitutes the +entire agreement between the parties with respect to the subject +matter hereof. This License shall be governed by the laws of the +United States and the State of California, except that body of +California law concerning conflicts of law. + +Where You are located in the province of Quebec, Canada, the following +clause applies: The parties hereby confirm that they have requested +that this License and all related documents be drafted in English. Les +parties ont exige que le present contrat et tous les documents +connexes soient rediges en anglais. + +EXHIBIT A. + +"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights +Reserved. + +This file contains Original Code and/or Modifications of Original Code +as defined in and that are subject to the Apple Public Source License +Version 2.0 (the 'License'). You may not use this file except in +compliance with the License. Please obtain a copy of the License at +http://www.opensource.apple.com/apsl/ and read it before using this +file. + +The Original Code and all software distributed under the License are +distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +Please see the License for the specific language governing rights and +limitations under the License." diff --git a/third_party/xnu/BUILD.gn b/third_party/xnu/BUILD.gn new file mode 100644 index 00000000..b6a94047 --- /dev/null +++ b/third_party/xnu/BUILD.gn @@ -0,0 +1,19 @@ +# 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("xnu") { + sources = [ + "EXTERNAL_HEADERS/mach-o/loader.h", + ] +} diff --git a/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h b/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h new file mode 100644 index 00000000..3b7f0ee3 --- /dev/null +++ b/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h @@ -0,0 +1,1531 @@ +/* + * Copyright (c) 1999-2010 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _MACHO_LOADER_H_ +#define _MACHO_LOADER_H_ + +/* + * This file describes the format of mach object files. + */ +#include <stdint.h> + +/* + * <mach/machine.h> is needed here for the cpu_type_t and cpu_subtype_t types + * and contains the constants for the possible values of these types. + */ +#include <mach/machine.h> + +/* + * <mach/vm_prot.h> is needed here for the vm_prot_t type and contains the + * constants that are or'ed together for the possible values of this type. + */ +#include <mach/vm_prot.h> + +/* + * The 32-bit mach header appears at the very beginning of the object file for + * 32-bit architectures. + */ +struct mach_header { + uint32_t magic; /* mach magic number identifier */ + cpu_type_t cputype; /* cpu specifier */ + cpu_subtype_t cpusubtype; /* machine specifier */ + uint32_t filetype; /* type of file */ + uint32_t ncmds; /* number of load commands */ + uint32_t sizeofcmds; /* the size of all the load commands */ + uint32_t flags; /* flags */ +}; + +/* Constant for the magic field of the mach_header (32-bit architectures) */ +#define MH_MAGIC 0xfeedface /* the mach magic number */ +#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */ + +/* + * The 64-bit mach header appears at the very beginning of object files for + * 64-bit architectures. + */ +struct mach_header_64 { + uint32_t magic; /* mach magic number identifier */ + cpu_type_t cputype; /* cpu specifier */ + cpu_subtype_t cpusubtype; /* machine specifier */ + uint32_t filetype; /* type of file */ + uint32_t ncmds; /* number of load commands */ + uint32_t sizeofcmds; /* the size of all the load commands */ + uint32_t flags; /* flags */ + uint32_t reserved; /* reserved */ +}; + +/* Constant for the magic field of the mach_header_64 (64-bit architectures) */ +#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */ +#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */ + +/* + * The layout of the file depends on the filetype. For all but the MH_OBJECT + * file type the segments are padded out and aligned on a segment alignment + * boundary for efficient demand pageing. The MH_EXECUTE, MH_FVMLIB, MH_DYLIB, + * MH_DYLINKER and MH_BUNDLE file types also have the headers included as part + * of their first segment. + * + * The file type MH_OBJECT is a compact format intended as output of the + * assembler and input (and possibly output) of the link editor (the .o + * format). All sections are in one unnamed segment with no segment padding. + * This format is used as an executable format when the file is so small the + * segment padding greatly increases its size. + * + * The file type MH_PRELOAD is an executable format intended for things that + * are not executed under the kernel (proms, stand alones, kernels, etc). The + * format can be executed under the kernel but may demand paged it and not + * preload it before execution. + * + * A core file is in MH_CORE format and can be any in an arbritray legal + * Mach-O file. + * + * Constants for the filetype field of the mach_header + */ +#define MH_OBJECT 0x1 /* relocatable object file */ +#define MH_EXECUTE 0x2 /* demand paged executable file */ +#define MH_FVMLIB 0x3 /* fixed VM shared library file */ +#define MH_CORE 0x4 /* core file */ +#define MH_PRELOAD 0x5 /* preloaded executable file */ +#define MH_DYLIB 0x6 /* dynamically bound shared library */ +#define MH_DYLINKER 0x7 /* dynamic link editor */ +#define MH_BUNDLE 0x8 /* dynamically bound bundle file */ +#define MH_DYLIB_STUB 0x9 /* shared library stub for static */ + /* linking only, no section contents */ +#define MH_DSYM 0xa /* companion file with only debug */ + /* sections */ +#define MH_KEXT_BUNDLE 0xb /* x86_64 kexts */ + +/* Constants for the flags field of the mach_header */ +#define MH_NOUNDEFS 0x1 /* the object file has no undefined + references */ +#define MH_INCRLINK 0x2 /* the object file is the output of an + incremental link against a base file + and can't be link edited again */ +#define MH_DYLDLINK 0x4 /* the object file is input for the + dynamic linker and can't be staticly + link edited again */ +#define MH_BINDATLOAD 0x8 /* the object file's undefined + references are bound by the dynamic + linker when loaded. */ +#define MH_PREBOUND 0x10 /* the file has its dynamic undefined + references prebound. */ +#define MH_SPLIT_SEGS 0x20 /* the file has its read-only and + read-write segments split */ +#define MH_LAZY_INIT 0x40 /* the shared library init routine is + to be run lazily via catching memory + faults to its writeable segments + (obsolete) */ +#define MH_TWOLEVEL 0x80 /* the image is using two-level name + space bindings */ +#define MH_FORCE_FLAT 0x100 /* the executable is forcing all images + to use flat name space bindings */ +#define MH_NOMULTIDEFS 0x200 /* this umbrella guarantees no multiple + defintions of symbols in its + sub-images so the two-level namespace + hints can always be used. */ +#define MH_NOFIXPREBINDING 0x400 /* do not have dyld notify the + prebinding agent about this + executable */ +#define MH_PREBINDABLE 0x800 /* the binary is not prebound but can + have its prebinding redone. only used + when MH_PREBOUND is not set. */ +#define MH_ALLMODSBOUND 0x1000 /* indicates that this binary binds to + all two-level namespace modules of + its dependent libraries. only used + when MH_PREBINDABLE and MH_TWOLEVEL + are both set. */ +#define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000/* safe to divide up the sections into + sub-sections via symbols for dead + code stripping */ +#define MH_CANONICAL 0x4000 /* the binary has been canonicalized + via the unprebind operation */ +#define MH_WEAK_DEFINES 0x8000 /* the final linked image contains + external weak symbols */ +#define MH_BINDS_TO_WEAK 0x10000 /* the final linked image uses + weak symbols */ + +#define MH_ALLOW_STACK_EXECUTION 0x20000/* When this bit is set, all stacks + in the task will be given stack + execution privilege. Only used in + MH_EXECUTE filetypes. */ +#define MH_ROOT_SAFE 0x40000 /* When this bit is set, the binary + declares it is safe for use in + processes with uid zero */ + +#define MH_SETUID_SAFE 0x80000 /* When this bit is set, the binary + declares it is safe for use in + processes when issetugid() is true */ + +#define MH_NO_REEXPORTED_DYLIBS 0x100000 /* When this bit is set on a dylib, + the static linker does not need to + examine dependent dylibs to see + if any are re-exported */ +#define MH_PIE 0x200000 /* When this bit is set, the OS will + load the main executable at a + random address. Only used in + MH_EXECUTE filetypes. */ +#define MH_DEAD_STRIPPABLE_DYLIB 0x400000 /* Only for use on dylibs. When + linking against a dylib that + has this bit set, the static linker + will automatically not create a + LC_LOAD_DYLIB load command to the + dylib if no symbols are being + referenced from the dylib. */ +#define MH_HAS_TLV_DESCRIPTORS 0x800000 /* Contains a section of type + S_THREAD_LOCAL_VARIABLES */ + +#define MH_NO_HEAP_EXECUTION 0x1000000 /* When this bit is set, the OS will + run the main executable with + a non-executable heap even on + platforms (e.g. i386) that don't + require it. Only used in MH_EXECUTE + filetypes. */ + +#define MH_APP_EXTENSION_SAFE 0x02000000 /* The code was linked for use in an + application extension. */ + +/* + * The load commands directly follow the mach_header. The total size of all + * of the commands is given by the sizeofcmds field in the mach_header. All + * load commands must have as their first two fields cmd and cmdsize. The cmd + * field is filled in with a constant for that command type. Each command type + * has a structure specifically for it. The cmdsize field is the size in bytes + * of the particular load command structure plus anything that follows it that + * is a part of the load command (i.e. section structures, strings, etc.). To + * advance to the next load command the cmdsize can be added to the offset or + * pointer of the current load command. The cmdsize for 32-bit architectures + * MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple + * of 8 bytes (these are forever the maximum alignment of any load commands). + * The padded bytes must be zero. All tables in the object file must also + * follow these rules so the file can be memory mapped. Otherwise the pointers + * to these tables will not work well or at all on some machines. With all + * padding zeroed like objects will compare byte for byte. + */ +struct load_command { + uint32_t cmd; /* type of load command */ + uint32_t cmdsize; /* total size of command in bytes */ +}; + +/* + * After MacOS X 10.1 when a new load command is added that is required to be + * understood by the dynamic linker for the image to execute properly the + * LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic + * linker sees such a load command it it does not understand will issue a + * "unknown load command required for execution" error and refuse to use the + * image. Other load commands without this bit that are not understood will + * simply be ignored. + */ +#define LC_REQ_DYLD 0x80000000 + +/* Constants for the cmd field of all load commands, the type */ +#define LC_SEGMENT 0x1 /* segment of this file to be mapped */ +#define LC_SYMTAB 0x2 /* link-edit stab symbol table info */ +#define LC_SYMSEG 0x3 /* link-edit gdb symbol table info (obsolete) */ +#define LC_THREAD 0x4 /* thread */ +#define LC_UNIXTHREAD 0x5 /* unix thread (includes a stack) */ +#define LC_LOADFVMLIB 0x6 /* load a specified fixed VM shared library */ +#define LC_IDFVMLIB 0x7 /* fixed VM shared library identification */ +#define LC_IDENT 0x8 /* object identification info (obsolete) */ +#define LC_FVMFILE 0x9 /* fixed VM file inclusion (internal use) */ +#define LC_PREPAGE 0xa /* prepage command (internal use) */ +#define LC_DYSYMTAB 0xb /* dynamic link-edit symbol table info */ +#define LC_LOAD_DYLIB 0xc /* load a dynamically linked shared library */ +#define LC_ID_DYLIB 0xd /* dynamically linked shared lib ident */ +#define LC_LOAD_DYLINKER 0xe /* load a dynamic linker */ +#define LC_ID_DYLINKER 0xf /* dynamic linker identification */ +#define LC_PREBOUND_DYLIB 0x10 /* modules prebound for a dynamically */ + /* linked shared library */ +#define LC_ROUTINES 0x11 /* image routines */ +#define LC_SUB_FRAMEWORK 0x12 /* sub framework */ +#define LC_SUB_UMBRELLA 0x13 /* sub umbrella */ +#define LC_SUB_CLIENT 0x14 /* sub client */ +#define LC_SUB_LIBRARY 0x15 /* sub library */ +#define LC_TWOLEVEL_HINTS 0x16 /* two-level namespace lookup hints */ +#define LC_PREBIND_CKSUM 0x17 /* prebind checksum */ + +/* + * load a dynamically linked shared library that is allowed to be missing + * (all symbols are weak imported). + */ +#define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD) + +#define LC_SEGMENT_64 0x19 /* 64-bit segment of this file to be + mapped */ +#define LC_ROUTINES_64 0x1a /* 64-bit image routines */ +#define LC_UUID 0x1b /* the uuid */ +#define LC_RPATH (0x1c | LC_REQ_DYLD) /* runpath additions */ +#define LC_CODE_SIGNATURE 0x1d /* local of code signature */ +#define LC_SEGMENT_SPLIT_INFO 0x1e /* local of info to split segments */ +#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) /* load and re-export dylib */ +#define LC_LAZY_LOAD_DYLIB 0x20 /* delay load of dylib until first use */ +#define LC_ENCRYPTION_INFO 0x21 /* encrypted segment information */ +#define LC_DYLD_INFO 0x22 /* compressed dyld information */ +#define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD) /* compressed dyld information only */ +#define LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD) /* load upward dylib */ +#define LC_VERSION_MIN_MACOSX 0x24 /* build for MacOSX min OS version */ +#define LC_VERSION_MIN_IPHONEOS 0x25 /* build for iPhoneOS min OS version */ +#define LC_FUNCTION_STARTS 0x26 /* compressed table of function start addresses */ +#define LC_DYLD_ENVIRONMENT 0x27 /* string for dyld to treat + like environment variable */ +#define LC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */ +#define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */ +#define LC_SOURCE_VERSION 0x2A /* source version used to build binary */ +#define LC_DYLIB_CODE_SIGN_DRS 0x2B /* Code signing DRs copied from linked dylibs */ +#define LC_ENCRYPTION_INFO_64 0x2C /* 64-bit encrypted segment information */ +#define LC_LINKER_OPTION 0x2D /* linker options in MH_OBJECT files */ +#define LC_LINKER_OPTIMIZATION_HINT 0x2E /* optimization hints in MH_OBJECT files */ +#define LC_VERSION_MIN_TVOS 0x2F /* build for AppleTV min OS version */ +#define LC_VERSION_MIN_WATCHOS 0x30 /* build for Watch min OS version */ +#define LC_NOTE 0x31 /* arbitrary data included within a Mach-O file */ +#define LC_BUILD_VERSION 0x32 /* build for platform min OS version */ + +/* + * A variable length string in a load command is represented by an lc_str + * union. The strings are stored just after the load command structure and + * the offset is from the start of the load command structure. The size + * of the string is reflected in the cmdsize field of the load command. + * Once again any padded bytes to bring the cmdsize field to a multiple + * of 4 bytes must be zero. + */ +union lc_str { + uint32_t offset; /* offset to the string */ +#ifndef __LP64__ + char *ptr; /* pointer to the string */ +#endif +}; + +/* + * The segment load command indicates that a part of this file is to be + * mapped into the task's address space. The size of this segment in memory, + * vmsize, maybe equal to or larger than the amount to map from this file, + * filesize. The file is mapped starting at fileoff to the beginning of + * the segment in memory, vmaddr. The rest of the memory of the segment, + * if any, is allocated zero fill on demand. The segment's maximum virtual + * memory protection and initial virtual memory protection are specified + * by the maxprot and initprot fields. If the segment has sections then the + * section structures directly follow the segment command and their size is + * reflected in cmdsize. + */ +struct segment_command { /* for 32-bit architectures */ + uint32_t cmd; /* LC_SEGMENT */ + uint32_t cmdsize; /* includes sizeof section structs */ + char segname[16]; /* segment name */ + uint32_t vmaddr; /* memory address of this segment */ + uint32_t vmsize; /* memory size of this segment */ + uint32_t fileoff; /* file offset of this segment */ + uint32_t filesize; /* amount to map from the file */ + vm_prot_t maxprot; /* maximum VM protection */ + vm_prot_t initprot; /* initial VM protection */ + uint32_t nsects; /* number of sections in segment */ + uint32_t flags; /* flags */ +}; + +/* + * The 64-bit segment load command indicates that a part of this file is to be + * mapped into a 64-bit task's address space. If the 64-bit segment has + * sections then section_64 structures directly follow the 64-bit segment + * command and their size is reflected in cmdsize. + */ +struct segment_command_64 { /* for 64-bit architectures */ + uint32_t cmd; /* LC_SEGMENT_64 */ + uint32_t cmdsize; /* includes sizeof section_64 structs */ + char segname[16]; /* segment name */ + uint64_t vmaddr; /* memory address of this segment */ + uint64_t vmsize; /* memory size of this segment */ + uint64_t fileoff; /* file offset of this segment */ + uint64_t filesize; /* amount to map from the file */ + vm_prot_t maxprot; /* maximum VM protection */ + vm_prot_t initprot; /* initial VM protection */ + uint32_t nsects; /* number of sections in segment */ + uint32_t flags; /* flags */ +}; + +/* Constants for the flags field of the segment_command */ +#define SG_HIGHVM 0x1 /* the file contents for this segment is for + the high part of the VM space, the low part + is zero filled (for stacks in core files) */ +#define SG_FVMLIB 0x2 /* this segment is the VM that is allocated by + a fixed VM library, for overlap checking in + the link editor */ +#define SG_NORELOC 0x4 /* this segment has nothing that was relocated + in it and nothing relocated to it, that is + it maybe safely replaced without relocation*/ +#define SG_PROTECTED_VERSION_1 0x8 /* This segment is protected. If the + segment starts at file offset 0, the + first page of the segment is not + protected. All other pages of the + segment are protected. */ + +/* + * A segment is made up of zero or more sections. Non-MH_OBJECT files have + * all of their segments with the proper sections in each, and padded to the + * specified segment alignment when produced by the link editor. The first + * segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header + * and load commands of the object file before its first section. The zero + * fill sections are always last in their segment (in all formats). This + * allows the zeroed segment padding to be mapped into memory where zero fill + * sections might be. The gigabyte zero fill sections, those with the section + * type S_GB_ZEROFILL, can only be in a segment with sections of this type. + * These segments are then placed after all other segments. + * + * The MH_OBJECT format has all of its sections in one segment for + * compactness. There is no padding to a specified segment boundary and the + * mach_header and load commands are not part of the segment. + * + * Sections with the same section name, sectname, going into the same segment, + * segname, are combined by the link editor. The resulting section is aligned + * to the maximum alignment of the combined sections and is the new section's + * alignment. The combined sections are aligned to their original alignment in + * the combined section. Any padded bytes to get the specified alignment are + * zeroed. + * + * The format of the relocation entries referenced by the reloff and nreloc + * fields of the section structure for mach object files is described in the + * header file <reloc.h>. + */ +struct section { /* for 32-bit architectures */ + char sectname[16]; /* name of this section */ + char segname[16]; /* segment this section goes in */ + uint32_t addr; /* memory address of this section */ + uint32_t size; /* size in bytes of this section */ + uint32_t offset; /* file offset of this section */ + uint32_t align; /* section alignment (power of 2) */ + uint32_t reloff; /* file offset of relocation entries */ + uint32_t nreloc; /* number of relocation entries */ + uint32_t flags; /* flags (section type and attributes)*/ + uint32_t reserved1; /* reserved (for offset or index) */ + uint32_t reserved2; /* reserved (for count or sizeof) */ +}; + +struct section_64 { /* for 64-bit architectures */ + char sectname[16]; /* name of this section */ + char segname[16]; /* segment this section goes in */ + uint64_t addr; /* memory address of this section */ + uint64_t size; /* size in bytes of this section */ + uint32_t offset; /* file offset of this section */ + uint32_t align; /* section alignment (power of 2) */ + uint32_t reloff; /* file offset of relocation entries */ + uint32_t nreloc; /* number of relocation entries */ + uint32_t flags; /* flags (section type and attributes)*/ + uint32_t reserved1; /* reserved (for offset or index) */ + uint32_t reserved2; /* reserved (for count or sizeof) */ + uint32_t reserved3; /* reserved */ +}; + +/* + * The flags field of a section structure is separated into two parts a section + * type and section attributes. The section types are mutually exclusive (it + * can only have one type) but the section attributes are not (it may have more + * than one attribute). + */ +#define SECTION_TYPE 0x000000ff /* 256 section types */ +#define SECTION_ATTRIBUTES 0xffffff00 /* 24 section attributes */ + +/* Constants for the type of a section */ +#define S_REGULAR 0x0 /* regular section */ +#define S_ZEROFILL 0x1 /* zero fill on demand section */ +#define S_CSTRING_LITERALS 0x2 /* section with only literal C strings*/ +#define S_4BYTE_LITERALS 0x3 /* section with only 4 byte literals */ +#define S_8BYTE_LITERALS 0x4 /* section with only 8 byte literals */ +#define S_LITERAL_POINTERS 0x5 /* section with only pointers to */ + /* literals */ +/* + * For the two types of symbol pointers sections and the symbol stubs section + * they have indirect symbol table entries. For each of the entries in the + * section the indirect symbol table entries, in corresponding order in the + * indirect symbol table, start at the index stored in the reserved1 field + * of the section structure. Since the indirect symbol table entries + * correspond to the entries in the section the number of indirect symbol table + * entries is inferred from the size of the section divided by the size of the + * entries in the section. For symbol pointers sections the size of the entries + * in the section is 4 bytes and for symbol stubs sections the byte size of the + * stubs is stored in the reserved2 field of the section structure. + */ +#define S_NON_LAZY_SYMBOL_POINTERS 0x6 /* section with only non-lazy + symbol pointers */ +#define S_LAZY_SYMBOL_POINTERS 0x7 /* section with only lazy symbol + pointers */ +#define S_SYMBOL_STUBS 0x8 /* section with only symbol + stubs, byte size of stub in + the reserved2 field */ +#define S_MOD_INIT_FUNC_POINTERS 0x9 /* section with only function + pointers for initialization*/ +#define S_MOD_TERM_FUNC_POINTERS 0xa /* section with only function + pointers for termination */ +#define S_COALESCED 0xb /* section contains symbols that + are to be coalesced */ +#define S_GB_ZEROFILL 0xc /* zero fill on demand section + (that can be larger than 4 + gigabytes) */ +#define S_INTERPOSING 0xd /* section with only pairs of + function pointers for + interposing */ +#define S_16BYTE_LITERALS 0xe /* section with only 16 byte + literals */ +#define S_DTRACE_DOF 0xf /* section contains + DTrace Object Format */ +#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 /* section with only lazy + symbol pointers to lazy + loaded dylibs */ +/* + * Section types to support thread local variables + */ +#define S_THREAD_LOCAL_REGULAR 0x11 /* template of initial + values for TLVs */ +#define S_THREAD_LOCAL_ZEROFILL 0x12 /* template of initial + values for TLVs */ +#define S_THREAD_LOCAL_VARIABLES 0x13 /* TLV descriptors */ +#define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14 /* pointers to TLV + descriptors */ +#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15 /* functions to call + to initialize TLV + values */ + +/* + * Constants for the section attributes part of the flags field of a section + * structure. + */ +#define SECTION_ATTRIBUTES_USR 0xff000000 /* User setable attributes */ +#define S_ATTR_PURE_INSTRUCTIONS 0x80000000 /* section contains only true + machine instructions */ +#define S_ATTR_NO_TOC 0x40000000 /* section contains coalesced + symbols that are not to be + in a ranlib table of + contents */ +#define S_ATTR_STRIP_STATIC_SYMS 0x20000000 /* ok to strip static symbols + in this section in files + with the MH_DYLDLINK flag */ +#define S_ATTR_NO_DEAD_STRIP 0x10000000 /* no dead stripping */ +#define S_ATTR_LIVE_SUPPORT 0x08000000 /* blocks are live if they + reference live blocks */ +#define S_ATTR_SELF_MODIFYING_CODE 0x04000000 /* Used with i386 code stubs + written on by dyld */ +/* + * If a segment contains any sections marked with S_ATTR_DEBUG then all + * sections in that segment must have this attribute. No section other than + * a section marked with this attribute may reference the contents of this + * section. A section with this attribute may contain no symbols and must have + * a section type S_REGULAR. The static linker will not copy section contents + * from sections with this attribute into its output file. These sections + * generally contain DWARF debugging info. + */ +#define S_ATTR_DEBUG 0x02000000 /* a debug section */ +#define SECTION_ATTRIBUTES_SYS 0x00ffff00 /* system setable attributes */ +#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 /* section contains some + machine instructions */ +#define S_ATTR_EXT_RELOC 0x00000200 /* section has external + relocation entries */ +#define S_ATTR_LOC_RELOC 0x00000100 /* section has local + relocation entries */ + + +/* + * The names of segments and sections in them are mostly meaningless to the + * link-editor. But there are few things to support traditional UNIX + * executables that require the link-editor and assembler to use some names + * agreed upon by convention. + * + * The initial protection of the "__TEXT" segment has write protection turned + * off (not writeable). + * + * The link-editor will allocate common symbols at the end of the "__common" + * section in the "__DATA" segment. It will create the section and segment + * if needed. + */ + +/* The currently known segment names and the section names in those segments */ + +#define SEG_PAGEZERO "__PAGEZERO" /* the pagezero segment which has no */ + /* protections and catches NULL */ + /* references for MH_EXECUTE files */ + + +#define SEG_TEXT "__TEXT" /* the tradition UNIX text segment */ +#define SECT_TEXT "__text" /* the real text part of the text */ + /* section no headers, and no padding */ +#define SECT_FVMLIB_INIT0 "__fvmlib_init0" /* the fvmlib initialization */ + /* section */ +#define SECT_FVMLIB_INIT1 "__fvmlib_init1" /* the section following the */ + /* fvmlib initialization */ + /* section */ + +#define SEG_DATA "__DATA" /* the tradition UNIX data segment */ +#define SECT_DATA "__data" /* the real initialized data section */ + /* no padding, no bss overlap */ +#define SECT_BSS "__bss" /* the real uninitialized data section*/ + /* no padding */ +#define SECT_COMMON "__common" /* the section common symbols are */ + /* allocated in by the link editor */ + +#define SEG_OBJC "__OBJC" /* objective-C runtime segment */ +#define SECT_OBJC_SYMBOLS "__symbol_table" /* symbol table */ +#define SECT_OBJC_MODULES "__module_info" /* module information */ +#define SECT_OBJC_STRINGS "__selector_strs" /* string table */ +#define SECT_OBJC_REFS "__selector_refs" /* string table */ + +#define SEG_ICON "__ICON" /* the icon segment */ +#define SECT_ICON_HEADER "__header" /* the icon headers */ +#define SECT_ICON_TIFF "__tiff" /* the icons in tiff format */ + +#define SEG_LINKEDIT "__LINKEDIT" /* the segment containing all structs */ + /* created and maintained by the link */ + /* editor. Created with -seglinkedit */ + /* option to ld(1) for MH_EXECUTE and */ + /* FVMLIB file types only */ + +#define SEG_UNIXSTACK "__UNIXSTACK" /* the unix stack segment */ + +#define SEG_IMPORT "__IMPORT" /* the segment for the self (dyld) */ + /* modifing code stubs that has read, */ + /* write and execute permissions */ + +/* + * Fixed virtual memory shared libraries are identified by two things. The + * target pathname (the name of the library as found for execution), and the + * minor version number. The address of where the headers are loaded is in + * header_addr. (THIS IS OBSOLETE and no longer supported). + */ +struct fvmlib { + union lc_str name; /* library's target pathname */ + uint32_t minor_version; /* library's minor version number */ + uint32_t header_addr; /* library's header address */ +}; + +/* + * A fixed virtual shared library (filetype == MH_FVMLIB in the mach header) + * contains a fvmlib_command (cmd == LC_IDFVMLIB) to identify the library. + * An object that uses a fixed virtual shared library also contains a + * fvmlib_command (cmd == LC_LOADFVMLIB) for each library it uses. + * (THIS IS OBSOLETE and no longer supported). + */ +struct fvmlib_command { + uint32_t cmd; /* LC_IDFVMLIB or LC_LOADFVMLIB */ + uint32_t cmdsize; /* includes pathname string */ + struct fvmlib fvmlib; /* the library identification */ +}; + +/* + * Dynamicly linked shared libraries are identified by two things. The + * pathname (the name of the library as found for execution), and the + * compatibility version number. The pathname must match and the compatibility + * number in the user of the library must be greater than or equal to the + * library being used. The time stamp is used to record the time a library was + * built and copied into user so it can be use to determined if the library used + * at runtime is exactly the same as used to built the program. + */ +struct dylib { + union lc_str name; /* library's path name */ + uint32_t timestamp; /* library's build time stamp */ + uint32_t current_version; /* library's current version number */ + uint32_t compatibility_version; /* library's compatibility vers number*/ +}; + +/* + * A dynamically linked shared library (filetype == MH_DYLIB in the mach header) + * contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library. + * An object that uses a dynamically linked shared library also contains a + * dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or + * LC_REEXPORT_DYLIB) for each library it uses. + */ +struct dylib_command { + uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, + LC_REEXPORT_DYLIB */ + uint32_t cmdsize; /* includes pathname string */ + struct dylib dylib; /* the library identification */ +}; + +/* + * A dynamically linked shared library may be a subframework of an umbrella + * framework. If so it will be linked with "-umbrella umbrella_name" where + * Where "umbrella_name" is the name of the umbrella framework. A subframework + * can only be linked against by its umbrella framework or other subframeworks + * that are part of the same umbrella framework. Otherwise the static link + * editor produces an error and states to link against the umbrella framework. + * The name of the umbrella framework for subframeworks is recorded in the + * following structure. + */ +struct sub_framework_command { + uint32_t cmd; /* LC_SUB_FRAMEWORK */ + uint32_t cmdsize; /* includes umbrella string */ + union lc_str umbrella; /* the umbrella framework name */ +}; + +/* + * For dynamically linked shared libraries that are subframework of an umbrella + * framework they can allow clients other than the umbrella framework or other + * subframeworks in the same umbrella framework. To do this the subframework + * is built with "-allowable_client client_name" and an LC_SUB_CLIENT load + * command is created for each -allowable_client flag. The client_name is + * usually a framework name. It can also be a name used for bundles clients + * where the bundle is built with "-client_name client_name". + */ +struct sub_client_command { + uint32_t cmd; /* LC_SUB_CLIENT */ + uint32_t cmdsize; /* includes client string */ + union lc_str client; /* the client name */ +}; + +/* + * A dynamically linked shared library may be a sub_umbrella of an umbrella + * framework. If so it will be linked with "-sub_umbrella umbrella_name" where + * Where "umbrella_name" is the name of the sub_umbrella framework. When + * staticly linking when -twolevel_namespace is in effect a twolevel namespace + * umbrella framework will only cause its subframeworks and those frameworks + * listed as sub_umbrella frameworks to be implicited linked in. Any other + * dependent dynamic libraries will not be linked it when -twolevel_namespace + * is in effect. The primary library recorded by the static linker when + * resolving a symbol in these libraries will be the umbrella framework. + * Zero or more sub_umbrella frameworks may be use by an umbrella framework. + * The name of a sub_umbrella framework is recorded in the following structure. + */ +struct sub_umbrella_command { + uint32_t cmd; /* LC_SUB_UMBRELLA */ + uint32_t cmdsize; /* includes sub_umbrella string */ + union lc_str sub_umbrella; /* the sub_umbrella framework name */ +}; + +/* + * A dynamically linked shared library may be a sub_library of another shared + * library. If so it will be linked with "-sub_library library_name" where + * Where "library_name" is the name of the sub_library shared library. When + * staticly linking when -twolevel_namespace is in effect a twolevel namespace + * shared library will only cause its subframeworks and those frameworks + * listed as sub_umbrella frameworks and libraries listed as sub_libraries to + * be implicited linked in. Any other dependent dynamic libraries will not be + * linked it when -twolevel_namespace is in effect. The primary library + * recorded by the static linker when resolving a symbol in these libraries + * will be the umbrella framework (or dynamic library). Zero or more sub_library + * shared libraries may be use by an umbrella framework or (or dynamic library). + * The name of a sub_library framework is recorded in the following structure. + * For example /usr/lib/libobjc_profile.A.dylib would be recorded as "libobjc". + */ +struct sub_library_command { + uint32_t cmd; /* LC_SUB_LIBRARY */ + uint32_t cmdsize; /* includes sub_library string */ + union lc_str sub_library; /* the sub_library name */ +}; + +/* + * A program (filetype == MH_EXECUTE) that is + * prebound to its dynamic libraries has one of these for each library that + * the static linker used in prebinding. It contains a bit vector for the + * modules in the library. The bits indicate which modules are bound (1) and + * which are not (0) from the library. The bit for module 0 is the low bit + * of the first byte. So the bit for the Nth module is: + * (linked_modules[N/8] >> N%8) & 1 + */ +struct prebound_dylib_command { + uint32_t cmd; /* LC_PREBOUND_DYLIB */ + uint32_t cmdsize; /* includes strings */ + union lc_str name; /* library's path name */ + uint32_t nmodules; /* number of modules in library */ + union lc_str linked_modules; /* bit vector of linked modules */ +}; + +/* + * A program that uses a dynamic linker contains a dylinker_command to identify + * the name of the dynamic linker (LC_LOAD_DYLINKER). And a dynamic linker + * contains a dylinker_command to identify the dynamic linker (LC_ID_DYLINKER). + * A file can have at most one of these. + * This struct is also used for the LC_DYLD_ENVIRONMENT load command and + * contains string for dyld to treat like environment variable. + */ +struct dylinker_command { + uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or + LC_DYLD_ENVIRONMENT */ + uint32_t cmdsize; /* includes pathname string */ + union lc_str name; /* dynamic linker's path name */ +}; + +/* + * Thread commands contain machine-specific data structures suitable for + * use in the thread state primitives. The machine specific data structures + * follow the struct thread_command as follows. + * Each flavor of machine specific data structure is preceded by an unsigned + * long constant for the flavor of that data structure, an uint32_t + * that is the count of longs of the size of the state data structure and then + * the state data structure follows. This triple may be repeated for many + * flavors. The constants for the flavors, counts and state data structure + * definitions are expected to be in the header file <machine/thread_status.h>. + * These machine specific data structures sizes must be multiples of + * 4 bytes The cmdsize reflects the total size of the thread_command + * and all of the sizes of the constants for the flavors, counts and state + * data structures. + * + * For executable objects that are unix processes there will be one + * thread_command (cmd == LC_UNIXTHREAD) created for it by the link-editor. + * This is the same as a LC_THREAD, except that a stack is automatically + * created (based on the shell's limit for the stack size). Command arguments + * and environment variables are copied onto that stack. + */ +struct thread_command { + uint32_t cmd; /* LC_THREAD or LC_UNIXTHREAD */ + uint32_t cmdsize; /* total size of this command */ + /* uint32_t flavor flavor of thread state */ + /* uint32_t count count of longs in thread state */ + /* struct XXX_thread_state state thread state for this flavor */ + /* ... */ +}; + +/* + * The routines command contains the address of the dynamic shared library + * initialization routine and an index into the module table for the module + * that defines the routine. Before any modules are used from the library the + * dynamic linker fully binds the module that defines the initialization routine + * and then calls it. This gets called before any module initialization + * routines (used for C++ static constructors) in the library. + */ +struct routines_command { /* for 32-bit architectures */ + uint32_t cmd; /* LC_ROUTINES */ + uint32_t cmdsize; /* total size of this command */ + uint32_t init_address; /* address of initialization routine */ + uint32_t init_module; /* index into the module table that */ + /* the init routine is defined in */ + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint32_t reserved4; + uint32_t reserved5; + uint32_t reserved6; +}; + +/* + * The 64-bit routines command. Same use as above. + */ +struct routines_command_64 { /* for 64-bit architectures */ + uint32_t cmd; /* LC_ROUTINES_64 */ + uint32_t cmdsize; /* total size of this command */ + uint64_t init_address; /* address of initialization routine */ + uint64_t init_module; /* index into the module table that */ + /* the init routine is defined in */ + uint64_t reserved1; + uint64_t reserved2; + uint64_t reserved3; + uint64_t reserved4; + uint64_t reserved5; + uint64_t reserved6; +}; + +/* + * The symtab_command contains the offsets and sizes of the link-edit 4.3BSD + * "stab" style symbol table information as described in the header files + * <nlist.h> and <stab.h>. + */ +struct symtab_command { + uint32_t cmd; /* LC_SYMTAB */ + uint32_t cmdsize; /* sizeof(struct symtab_command) */ + uint32_t symoff; /* symbol table offset */ + uint32_t nsyms; /* number of symbol table entries */ + uint32_t stroff; /* string table offset */ + uint32_t strsize; /* string table size in bytes */ +}; + +/* + * This is the second set of the symbolic information which is used to support + * the data structures for the dynamically link editor. + * + * The original set of symbolic information in the symtab_command which contains + * the symbol and string tables must also be present when this load command is + * present. When this load command is present the symbol table is organized + * into three groups of symbols: + * local symbols (static and debugging symbols) - grouped by module + * defined external symbols - grouped by module (sorted by name if not lib) + * undefined external symbols (sorted by name if MH_BINDATLOAD is not set, + * and in order the were seen by the static + * linker if MH_BINDATLOAD is set) + * In this load command there are offsets and counts to each of the three groups + * of symbols. + * + * This load command contains a the offsets and sizes of the following new + * symbolic information tables: + * table of contents + * module table + * reference symbol table + * indirect symbol table + * The first three tables above (the table of contents, module table and + * reference symbol table) are only present if the file is a dynamically linked + * shared library. For executable and object modules, which are files + * containing only one module, the information that would be in these three + * tables is determined as follows: + * table of contents - the defined external symbols are sorted by name + * module table - the file contains only one module so everything in the + * file is part of the module. + * reference symbol table - is the defined and undefined external symbols + * + * For dynamically linked shared library files this load command also contains + * offsets and sizes to the pool of relocation entries for all sections + * separated into two groups: + * external relocation entries + * local relocation entries + * For executable and object modules the relocation entries continue to hang + * off the section structures. + */ +struct dysymtab_command { + uint32_t cmd; /* LC_DYSYMTAB */ + uint32_t cmdsize; /* sizeof(struct dysymtab_command) */ + + /* + * The symbols indicated by symoff and nsyms of the LC_SYMTAB load command + * are grouped into the following three groups: + * local symbols (further grouped by the module they are from) + * defined external symbols (further grouped by the module they are from) + * undefined symbols + * + * The local symbols are used only for debugging. The dynamic binding + * process may have to use them to indicate to the debugger the local + * symbols for a module that is being bound. + * + * The last two groups are used by the dynamic binding process to do the + * binding (indirectly through the module table and the reference symbol + * table when this is a dynamically linked shared library file). + */ + uint32_t ilocalsym; /* index to local symbols */ + uint32_t nlocalsym; /* number of local symbols */ + + uint32_t iextdefsym;/* index to externally defined symbols */ + uint32_t nextdefsym;/* number of externally defined symbols */ + + uint32_t iundefsym; /* index to undefined symbols */ + uint32_t nundefsym; /* number of undefined symbols */ + + /* + * For the for the dynamic binding process to find which module a symbol + * is defined in the table of contents is used (analogous to the ranlib + * structure in an archive) which maps defined external symbols to modules + * they are defined in. This exists only in a dynamically linked shared + * library file. For executable and object modules the defined external + * symbols are sorted by name and is use as the table of contents. + */ + uint32_t tocoff; /* file offset to table of contents */ + uint32_t ntoc; /* number of entries in table of contents */ + + /* + * To support dynamic binding of "modules" (whole object files) the symbol + * table must reflect the modules that the file was created from. This is + * done by having a module table that has indexes and counts into the merged + * tables for each module. The module structure that these two entries + * refer to is described below. This exists only in a dynamically linked + * shared library file. For executable and object modules the file only + * contains one module so everything in the file belongs to the module. + */ + uint32_t modtaboff; /* file offset to module table */ + uint32_t nmodtab; /* number of module table entries */ + + /* + * To support dynamic module binding the module structure for each module + * indicates the external references (defined and undefined) each module + * makes. For each module there is an offset and a count into the + * reference symbol table for the symbols that the module references. + * This exists only in a dynamically linked shared library file. For + * executable and object modules the defined external symbols and the + * undefined external symbols indicates the external references. + */ + uint32_t extrefsymoff; /* offset to referenced symbol table */ + uint32_t nextrefsyms; /* number of referenced symbol table entries */ + + /* + * The sections that contain "symbol pointers" and "routine stubs" have + * indexes and (implied counts based on the size of the section and fixed + * size of the entry) into the "indirect symbol" table for each pointer + * and stub. For every section of these two types the index into the + * indirect symbol table is stored in the section header in the field + * reserved1. An indirect symbol table entry is simply a 32bit index into + * the symbol table to the symbol that the pointer or stub is referring to. + * The indirect symbol table is ordered to match the entries in the section. + */ + uint32_t indirectsymoff; /* file offset to the indirect symbol table */ + uint32_t nindirectsyms; /* number of indirect symbol table entries */ + + /* + * To support relocating an individual module in a library file quickly the + * external relocation entries for each module in the library need to be + * accessed efficiently. Since the relocation entries can't be accessed + * through the section headers for a library file they are separated into + * groups of local and external entries further grouped by module. In this + * case the presents of this load command who's extreloff, nextrel, + * locreloff and nlocrel fields are non-zero indicates that the relocation + * entries of non-merged sections are not referenced through the section + * structures (and the reloff and nreloc fields in the section headers are + * set to zero). + * + * Since the relocation entries are not accessed through the section headers + * this requires the r_address field to be something other than a section + * offset to identify the item to be relocated. In this case r_address is + * set to the offset from the vmaddr of the first LC_SEGMENT command. + * For MH_SPLIT_SEGS images r_address is set to the the offset from the + * vmaddr of the first read-write LC_SEGMENT command. + * + * The relocation entries are grouped by module and the module table + * entries have indexes and counts into them for the group of external + * relocation entries for that the module. + * + * For sections that are merged across modules there must not be any + * remaining external relocation entries for them (for merged sections + * remaining relocation entries must be local). + */ + uint32_t extreloff; /* offset to external relocation entries */ + uint32_t nextrel; /* number of external relocation entries */ + + /* + * All the local relocation entries are grouped together (they are not + * grouped by their module since they are only used if the object is moved + * from it staticly link edited address). + */ + uint32_t locreloff; /* offset to local relocation entries */ + uint32_t nlocrel; /* number of local relocation entries */ + +}; + +/* + * An indirect symbol table entry is simply a 32bit index into the symbol table + * to the symbol that the pointer or stub is refering to. Unless it is for a + * non-lazy symbol pointer section for a defined symbol which strip(1) as + * removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. If the + * symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that. + */ +#define INDIRECT_SYMBOL_LOCAL 0x80000000 +#define INDIRECT_SYMBOL_ABS 0x40000000 + + +/* a table of contents entry */ +struct dylib_table_of_contents { + uint32_t symbol_index; /* the defined external symbol + (index into the symbol table) */ + uint32_t module_index; /* index into the module table this symbol + is defined in */ +}; + +/* a module table entry */ +struct dylib_module { + uint32_t module_name; /* the module name (index into string table) */ + + uint32_t iextdefsym; /* index into externally defined symbols */ + uint32_t nextdefsym; /* number of externally defined symbols */ + uint32_t irefsym; /* index into reference symbol table */ + uint32_t nrefsym; /* number of reference symbol table entries */ + uint32_t ilocalsym; /* index into symbols for local symbols */ + uint32_t nlocalsym; /* number of local symbols */ + + uint32_t iextrel; /* index into external relocation entries */ + uint32_t nextrel; /* number of external relocation entries */ + + uint32_t iinit_iterm; /* low 16 bits are the index into the init + section, high 16 bits are the index into + the term section */ + uint32_t ninit_nterm; /* low 16 bits are the number of init section + entries, high 16 bits are the number of + term section entries */ + + uint32_t /* for this module address of the start of */ + objc_module_info_addr; /* the (__OBJC,__module_info) section */ + uint32_t /* for this module size of */ + objc_module_info_size; /* the (__OBJC,__module_info) section */ +}; + +/* a 64-bit module table entry */ +struct dylib_module_64 { + uint32_t module_name; /* the module name (index into string table) */ + + uint32_t iextdefsym; /* index into externally defined symbols */ + uint32_t nextdefsym; /* number of externally defined symbols */ + uint32_t irefsym; /* index into reference symbol table */ + uint32_t nrefsym; /* number of reference symbol table entries */ + uint32_t ilocalsym; /* index into symbols for local symbols */ + uint32_t nlocalsym; /* number of local symbols */ + + uint32_t iextrel; /* index into external relocation entries */ + uint32_t nextrel; /* number of external relocation entries */ + + uint32_t iinit_iterm; /* low 16 bits are the index into the init + section, high 16 bits are the index into + the term section */ + uint32_t ninit_nterm; /* low 16 bits are the number of init section + entries, high 16 bits are the number of + term section entries */ + + uint32_t /* for this module size of */ + objc_module_info_size; /* the (__OBJC,__module_info) section */ + uint64_t /* for this module address of the start of */ + objc_module_info_addr; /* the (__OBJC,__module_info) section */ +}; + +/* + * The entries in the reference symbol table are used when loading the module + * (both by the static and dynamic link editors) and if the module is unloaded + * or replaced. Therefore all external symbols (defined and undefined) are + * listed in the module's reference table. The flags describe the type of + * reference that is being made. The constants for the flags are defined in + * <mach-o/nlist.h> as they are also used for symbol table entries. + */ +struct dylib_reference { + uint32_t isym:24, /* index into the symbol table */ + flags:8; /* flags to indicate the type of reference */ +}; + +/* + * The twolevel_hints_command contains the offset and number of hints in the + * two-level namespace lookup hints table. + */ +struct twolevel_hints_command { + uint32_t cmd; /* LC_TWOLEVEL_HINTS */ + uint32_t cmdsize; /* sizeof(struct twolevel_hints_command) */ + uint32_t offset; /* offset to the hint table */ + uint32_t nhints; /* number of hints in the hint table */ +}; + +/* + * The entries in the two-level namespace lookup hints table are twolevel_hint + * structs. These provide hints to the dynamic link editor where to start + * looking for an undefined symbol in a two-level namespace image. The + * isub_image field is an index into the sub-images (sub-frameworks and + * sub-umbrellas list) that made up the two-level image that the undefined + * symbol was found in when it was built by the static link editor. If + * isub-image is 0 the the symbol is expected to be defined in library and not + * in the sub-images. If isub-image is non-zero it is an index into the array + * of sub-images for the umbrella with the first index in the sub-images being + * 1. The array of sub-images is the ordered list of sub-images of the umbrella + * that would be searched for a symbol that has the umbrella recorded as its + * primary library. The table of contents index is an index into the + * library's table of contents. This is used as the starting point of the + * binary search or a directed linear search. + */ +struct twolevel_hint { + uint32_t + isub_image:8, /* index into the sub images */ + itoc:24; /* index into the table of contents */ +}; + +/* + * The prebind_cksum_command contains the value of the original check sum for + * prebound files or zero. When a prebound file is first created or modified + * for other than updating its prebinding information the value of the check sum + * is set to zero. When the file has it prebinding re-done and if the value of + * the check sum is zero the original check sum is calculated and stored in + * cksum field of this load command in the output file. If when the prebinding + * is re-done and the cksum field is non-zero it is left unchanged from the + * input file. + */ +struct prebind_cksum_command { + uint32_t cmd; /* LC_PREBIND_CKSUM */ + uint32_t cmdsize; /* sizeof(struct prebind_cksum_command) */ + uint32_t cksum; /* the check sum or zero */ +}; + +/* + * The uuid load command contains a single 128-bit unique random number that + * identifies an object produced by the static link editor. + */ +struct uuid_command { + uint32_t cmd; /* LC_UUID */ + uint32_t cmdsize; /* sizeof(struct uuid_command) */ + uint8_t uuid[16]; /* the 128-bit uuid */ +}; + +/* + * The rpath_command contains a path which at runtime should be added to + * the current run path used to find @rpath prefixed dylibs. + */ +struct rpath_command { + uint32_t cmd; /* LC_RPATH */ + uint32_t cmdsize; /* includes string */ + union lc_str path; /* path to add to run path */ +}; + +/* + * The linkedit_data_command contains the offsets and sizes of a blob + * of data in the __LINKEDIT segment. + */ +struct linkedit_data_command { + uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, + LC_FUNCTION_STARTS, LC_DATA_IN_CODE, + LC_DYLIB_CODE_SIGN_DRS or + LC_LINKER_OPTIMIZATION_HINT. */ + uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */ + uint32_t dataoff; /* file offset of data in __LINKEDIT segment */ + uint32_t datasize; /* file size of data in __LINKEDIT segment */ +}; + +/* + * The encryption_info_command contains the file offset and size of an + * of an encrypted segment. + */ +struct encryption_info_command { + uint32_t cmd; /* LC_ENCRYPTION_INFO */ + uint32_t cmdsize; /* sizeof(struct encryption_info_command) */ + uint32_t cryptoff; /* file offset of encrypted range */ + uint32_t cryptsize; /* file size of encrypted range */ + uint32_t cryptid; /* which enryption system, + 0 means not-encrypted yet */ +}; + +/* + * The encryption_info_command_64 contains the file offset and size of an + * of an encrypted segment (for use in x86_64 targets). + */ +struct encryption_info_command_64 { + uint32_t cmd; /* LC_ENCRYPTION_INFO_64 */ + uint32_t cmdsize; /* sizeof(struct encryption_info_command_64) */ + uint32_t cryptoff; /* file offset of encrypted range */ + uint32_t cryptsize; /* file size of encrypted range */ + uint32_t cryptid; /* which enryption system, + 0 means not-encrypted yet */ + uint32_t pad; /* padding to make this struct's size a multiple + of 8 bytes */ +}; + +/* + * The version_min_command contains the min OS version on which this + * binary was built to run. + */ +struct version_min_command { + uint32_t cmd; /* LC_VERSION_MIN_MACOSX or + LC_VERSION_MIN_IPHONEOS or + LC_VERSION_MIN_WATCHOS or + LC_VERSION_MIN_TVOS */ + uint32_t cmdsize; /* sizeof(struct min_version_command) */ + uint32_t version; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ +}; + +/* + * The build_version_command contains the min OS version on which this + * binary was built to run for its platform. The list of known platforms and + * tool values following it. + */ +struct build_version_command { + uint32_t cmd; /* LC_BUILD_VERSION */ + uint32_t cmdsize; /* sizeof(struct build_version_command) plus */ + /* ntools * sizeof(struct build_tool_version) */ + uint32_t platform; /* platform */ + uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */ + uint32_t ntools; /* number of tool entries following this */ +}; + +struct build_tool_version { + uint32_t tool; /* enum for the tool */ + uint32_t version; /* version number of the tool */ +}; + +/* Known values for the platform field above. */ +#define PLATFORM_MACOS 1 +#define PLATFORM_IOS 2 +#define PLATFORM_TVOS 3 +#define PLATFORM_WATCHOS 4 + +/* Known values for the tool field above. */ +#define TOOL_CLANG 1 +#define TOOL_SWIFT 2 +#define TOOL_LD 3 + +/* + * The dyld_info_command contains the file offsets and sizes of + * the new compressed form of the information dyld needs to + * load the image. This information is used by dyld on Mac OS X + * 10.6 and later. All information pointed to by this command + * is encoded using byte streams, so no endian swapping is needed + * to interpret it. + */ +struct dyld_info_command { + uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */ + uint32_t cmdsize; /* sizeof(struct dyld_info_command) */ + + /* + * Dyld rebases an image whenever dyld loads it at an address different + * from its preferred address. The rebase information is a stream + * of byte sized opcodes whose symbolic names start with REBASE_OPCODE_. + * Conceptually the rebase information is a table of tuples: + * <seg-index, seg-offset, type> + * The opcodes are a compressed way to encode the table by only + * encoding when a column changes. In addition simple patterns + * like "every n'th offset for m times" can be encoded in a few + * bytes. + */ + uint32_t rebase_off; /* file offset to rebase info */ + uint32_t rebase_size; /* size of rebase info */ + + /* + * Dyld binds an image during the loading process, if the image + * requires any pointers to be initialized to symbols in other images. + * The bind information is a stream of byte sized + * opcodes whose symbolic names start with BIND_OPCODE_. + * Conceptually the bind information is a table of tuples: + * <seg-index, seg-offset, type, symbol-library-ordinal, symbol-name, addend> + * The opcodes are a compressed way to encode the table by only + * encoding when a column changes. In addition simple patterns + * like for runs of pointers initialzed to the same value can be + * encoded in a few bytes. + */ + uint32_t bind_off; /* file offset to binding info */ + uint32_t bind_size; /* size of binding info */ + + /* + * Some C++ programs require dyld to unique symbols so that all + * images in the process use the same copy of some code/data. + * This step is done after binding. The content of the weak_bind + * info is an opcode stream like the bind_info. But it is sorted + * alphabetically by symbol name. This enable dyld to walk + * all images with weak binding information in order and look + * for collisions. If there are no collisions, dyld does + * no updating. That means that some fixups are also encoded + * in the bind_info. For instance, all calls to "operator new" + * are first bound to libstdc++.dylib using the information + * in bind_info. Then if some image overrides operator new + * that is detected when the weak_bind information is processed + * and the call to operator new is then rebound. + */ + uint32_t weak_bind_off; /* file offset to weak binding info */ + uint32_t weak_bind_size; /* size of weak binding info */ + + /* + * Some uses of external symbols do not need to be bound immediately. + * Instead they can be lazily bound on first use. The lazy_bind + * are contains a stream of BIND opcodes to bind all lazy symbols. + * Normal use is that dyld ignores the lazy_bind section when + * loading an image. Instead the static linker arranged for the + * lazy pointer to initially point to a helper function which + * pushes the offset into the lazy_bind area for the symbol + * needing to be bound, then jumps to dyld which simply adds + * the offset to lazy_bind_off to get the information on what + * to bind. + */ + uint32_t lazy_bind_off; /* file offset to lazy binding info */ + uint32_t lazy_bind_size; /* size of lazy binding infs */ + + /* + * The symbols exported by a dylib are encoded in a trie. This + * is a compact representation that factors out common prefixes. + * It also reduces LINKEDIT pages in RAM because it encodes all + * information (name, address, flags) in one small, contiguous range. + * The export area is a stream of nodes. The first node sequentially + * is the start node for the trie. + * + * Nodes for a symbol start with a uleb128 that is the length of + * the exported symbol information for the string so far. + * If there is no exported symbol, the node starts with a zero byte. + * If there is exported info, it follows the length. + * + * First is a uleb128 containing flags. Normally, it is followed by + * a uleb128 encoded offset which is location of the content named + * by the symbol from the mach_header for the image. If the flags + * is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is + * a uleb128 encoded library ordinal, then a zero terminated + * UTF8 string. If the string is zero length, then the symbol + * is re-export from the specified dylib with the same name. + * If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following + * the flags is two uleb128s: the stub offset and the resolver offset. + * The stub is used by non-lazy pointers. The resolver is used + * by lazy pointers and must be called to get the actual address to use. + * + * After the optional exported symbol information is a byte of + * how many edges (0-255) that this node has leaving it, + * followed by each edge. + * Each edge is a zero terminated UTF8 of the addition chars + * in the symbol, followed by a uleb128 offset for the node that + * edge points to. + * + */ + uint32_t export_off; /* file offset to lazy binding info */ + uint32_t export_size; /* size of lazy binding infs */ +}; + +/* + * The following are used to encode rebasing information + */ +#define REBASE_TYPE_POINTER 1 +#define REBASE_TYPE_TEXT_ABSOLUTE32 2 +#define REBASE_TYPE_TEXT_PCREL32 3 + +#define REBASE_OPCODE_MASK 0xF0 +#define REBASE_IMMEDIATE_MASK 0x0F +#define REBASE_OPCODE_DONE 0x00 +#define REBASE_OPCODE_SET_TYPE_IMM 0x10 +#define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20 +#define REBASE_OPCODE_ADD_ADDR_ULEB 0x30 +#define REBASE_OPCODE_ADD_ADDR_IMM_SCALED 0x40 +#define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50 +#define REBASE_OPCODE_DO_REBASE_ULEB_TIMES 0x60 +#define REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB 0x70 +#define REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB 0x80 + + +/* + * The following are used to encode binding information + */ +#define BIND_TYPE_POINTER 1 +#define BIND_TYPE_TEXT_ABSOLUTE32 2 +#define BIND_TYPE_TEXT_PCREL32 3 + +#define BIND_SPECIAL_DYLIB_SELF 0 +#define BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE -1 +#define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2 + +#define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1 +#define BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION 0x8 + +#define BIND_OPCODE_MASK 0xF0 +#define BIND_IMMEDIATE_MASK 0x0F +#define BIND_OPCODE_DONE 0x00 +#define BIND_OPCODE_SET_DYLIB_ORDINAL_IMM 0x10 +#define BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB 0x20 +#define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30 +#define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40 +#define BIND_OPCODE_SET_TYPE_IMM 0x50 +#define BIND_OPCODE_SET_ADDEND_SLEB 0x60 +#define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70 +#define BIND_OPCODE_ADD_ADDR_ULEB 0x80 +#define BIND_OPCODE_DO_BIND 0x90 +#define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xA0 +#define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xB0 +#define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xC0 + + +/* + * The following are used on the flags byte of a terminal node + * in the export information. + */ +#define EXPORT_SYMBOL_FLAGS_KIND_MASK 0x03 +#define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00 +#define EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL 0x01 +#define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04 +#define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08 +#define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10 + +/* + * The linker_option_command contains linker options embedded in object files. + */ +struct linker_option_command { + uint32_t cmd; /* LC_LINKER_OPTION only used in MH_OBJECT filetypes */ + uint32_t cmdsize; + uint32_t count; /* number of strings */ + /* concatenation of zero terminated UTF8 strings. + Zero filled at end to align */ +}; + +/* + * The symseg_command contains the offset and size of the GNU style + * symbol table information as described in the header file <symseg.h>. + * The symbol roots of the symbol segments must also be aligned properly + * in the file. So the requirement of keeping the offsets aligned to a + * multiple of a 4 bytes translates to the length field of the symbol + * roots also being a multiple of a long. Also the padding must again be + * zeroed. (THIS IS OBSOLETE and no longer supported). + */ +struct symseg_command { + uint32_t cmd; /* LC_SYMSEG */ + uint32_t cmdsize; /* sizeof(struct symseg_command) */ + uint32_t offset; /* symbol segment offset */ + uint32_t size; /* symbol segment size in bytes */ +}; + +/* + * The ident_command contains a free format string table following the + * ident_command structure. The strings are null terminated and the size of + * the command is padded out with zero bytes to a multiple of 4 bytes/ + * (THIS IS OBSOLETE and no longer supported). + */ +struct ident_command { + uint32_t cmd; /* LC_IDENT */ + uint32_t cmdsize; /* strings that follow this command */ +}; + +/* + * The fvmfile_command contains a reference to a file to be loaded at the + * specified virtual address. (Presently, this command is reserved for + * internal use. The kernel ignores this command when loading a program into + * memory). + */ +struct fvmfile_command { + uint32_t cmd; /* LC_FVMFILE */ + uint32_t cmdsize; /* includes pathname string */ + union lc_str name; /* files pathname */ + uint32_t header_addr; /* files virtual address */ +}; + + +/* + * The entry_point_command is a replacement for thread_command. + * It is used for main executables to specify the location (file offset) + * of main(). If -stack_size was used at link time, the stacksize + * field will contain the stack size need for the main thread. + */ +struct entry_point_command { + uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */ + uint32_t cmdsize; /* 24 */ + uint64_t entryoff; /* file (__TEXT) offset of main() */ + uint64_t stacksize;/* if not zero, initial stack size */ +}; + + +/* + * The source_version_command is an optional load command containing + * the version of the sources used to build the binary. + */ +struct source_version_command { + uint32_t cmd; /* LC_SOURCE_VERSION */ + uint32_t cmdsize; /* 16 */ + uint64_t version; /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */ +}; + + +/* + * The LC_DATA_IN_CODE load commands uses a linkedit_data_command + * to point to an array of data_in_code_entry entries. Each entry + * describes a range of data in a code section. + */ +struct data_in_code_entry { + uint32_t offset; /* from mach_header to start of data range*/ + uint16_t length; /* number of bytes in data range */ + uint16_t kind; /* a DICE_KIND_* value */ +}; +#define DICE_KIND_DATA 0x0001 +#define DICE_KIND_JUMP_TABLE8 0x0002 +#define DICE_KIND_JUMP_TABLE16 0x0003 +#define DICE_KIND_JUMP_TABLE32 0x0004 +#define DICE_KIND_ABS_JUMP_TABLE32 0x0005 + + + +/* + * Sections of type S_THREAD_LOCAL_VARIABLES contain an array + * of tlv_descriptor structures. + */ +struct tlv_descriptor +{ + void* (*thunk)(struct tlv_descriptor*); + unsigned long key; + unsigned long offset; +}; + +/* + * LC_NOTE commands describe a region of arbitrary data included in a Mach-O + * file. Its initial use is to record extra data in MH_CORE files. + */ +struct note_command { + uint32_t cmd; /* LC_NOTE */ + uint32_t cmdsize; /* sizeof(struct note_command) */ + char data_owner[16]; /* owner name for this LC_NOTE */ + uint64_t offset; /* file offset of this data */ + uint64_t size; /* length of data region */ +}; + +#endif /* _MACHO_LOADER_H_ */ diff --git a/third_party/xnu/README.crashpad b/third_party/xnu/README.crashpad new file mode 100644 index 00000000..274faf16 --- /dev/null +++ b/third_party/xnu/README.crashpad @@ -0,0 +1,19 @@ +Name: XNU +Short Name: xnu +URL: https://opensource.apple.com/source/xnu/ +URL: https://opensource.apple.com/tarballs/xnu/ +Version: 4903.221.2 (from macOS 10.14.1) +License: APSL 2.0 +License File: APPLE_LICENSE +Security Critical: no + +Description: +XNU is the operating system kernel used on macOS and other Apple systems. + +Local Modifications: + - Only EXTERNAL_HEADERS/mach-o/loader.h is included. Its #includes of + <mach/machine/thread_status.h> and <architecture/byte_order.h> have been + removed as unnecessary. Note that its #includes of <mach/machine.h> and + <mach/vm_prot.h> have been retained but these headers have not been provided. + External headers must be made available to provide the cpu_type_t, + cpu_subtype_t, and vm_prot_t types. From 708367f5badf776323d2e91fca162409a0995f57 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 27 Feb 2019 17:40:16 -0500 Subject: [PATCH 149/401] POSIX: ScopedMmap length refinement 9d26012e9c73 relaxed the requirement on ScopedMmap such that the length of the region supervised no longer needed to be provided as a round number of pages. This was accomplished by internally rounding up the provided length to a page length. Unfortunately, this made ScopedMmap::len() return something other than the passed-in length, which is undesirable. This change makes ScopedMmap store the passed-in length internally, making it available unmodified via the accessor, and rounding it up to page length at internal points of use. Change-Id: I827925af68e38f33bfa3cee535db0f098884fc6b Reviewed-on: https://chromium-review.googlesource.com/c/1492774 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- util/posix/scoped_mmap.cc | 26 +++++++++++++++----------- util/posix/scoped_mmap.h | 5 +++++ util/posix/scoped_mmap_test.cc | 12 ++++++------ 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/util/posix/scoped_mmap.cc b/util/posix/scoped_mmap.cc index 0965fd67..fbf47fae 100644 --- a/util/posix/scoped_mmap.cc +++ b/util/posix/scoped_mmap.cc @@ -33,6 +33,11 @@ bool Munmap(uintptr_t addr, size_t len) { return true; } +size_t RoundPage(size_t size) { + const size_t kPageMask = base::checked_cast<size_t>(getpagesize()) - 1; + return (size + kPageMask) & ~kPageMask; +} + } // namespace namespace crashpad { @@ -41,7 +46,7 @@ ScopedMmap::ScopedMmap() {} ScopedMmap::~ScopedMmap() { if (is_valid()) { - Munmap(reinterpret_cast<uintptr_t>(addr_), len_); + Munmap(reinterpret_cast<uintptr_t>(addr_), RoundPage(len_)); } } @@ -51,29 +56,28 @@ bool ScopedMmap::Reset() { bool ScopedMmap::ResetAddrLen(void* addr, size_t len) { const uintptr_t new_addr = reinterpret_cast<uintptr_t>(addr); + const size_t new_len_round = RoundPage(len); if (addr == MAP_FAILED) { DCHECK_EQ(len, 0u); } else { - // Round |len| up to the next page. - const size_t kPageMask = base::checked_cast<size_t>(getpagesize()) - 1; - len = (len + kPageMask) & ~kPageMask; - DCHECK_NE(len, 0u); DCHECK_EQ(new_addr % getpagesize(), 0u); - DCHECK((base::CheckedNumeric<uintptr_t>(new_addr) + (len - 1)).IsValid()); + DCHECK((base::CheckedNumeric<uintptr_t>(new_addr) + (new_len_round - 1)) + .IsValid()); } bool result = true; if (is_valid()) { const uintptr_t old_addr = reinterpret_cast<uintptr_t>(addr_); + const size_t old_len_round = RoundPage(len_); if (old_addr < new_addr) { - result &= Munmap(old_addr, std::min(len_, new_addr - old_addr)); + result &= Munmap(old_addr, std::min(old_len_round, new_addr - old_addr)); } - if (old_addr + len_ > new_addr + len) { - uintptr_t unmap_start = std::max(old_addr, new_addr + len); - result &= Munmap(unmap_start, old_addr + len_ - unmap_start); + 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); } } @@ -108,7 +112,7 @@ bool ScopedMmap::ResetMmap(void* addr, } bool ScopedMmap::Mprotect(int prot) { - if (mprotect(addr_, len_, prot) < 0) { + if (mprotect(addr_, RoundPage(len_), prot) < 0) { PLOG(ERROR) << "mprotect"; return false; } diff --git a/util/posix/scoped_mmap.h b/util/posix/scoped_mmap.h index b0ff3dc0..9f22372b 100644 --- a/util/posix/scoped_mmap.h +++ b/util/posix/scoped_mmap.h @@ -91,6 +91,11 @@ class ScopedMmap { } //! \brief Returns the size of the memory-mapped region. + //! + //! This is the value originally passed to ResetAddrLen() or ResetMmap(), or + //! after Reset(), `0`. It may not be a round number of pages. Providing the + //! passed-in value is intended to ease tracking the intended lengths of + //! memory-mapped regions backed by files whose sizes are not whole pages. size_t len() const { return len_; } private: diff --git a/util/posix/scoped_mmap_test.cc b/util/posix/scoped_mmap_test.cc index e32fa159..5279fdb8 100644 --- a/util/posix/scoped_mmap_test.cc +++ b/util/posix/scoped_mmap_test.cc @@ -309,7 +309,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(ScopedMmapResetMmap(&mapping, kHalfPageSize)); EXPECT_TRUE(mapping.is_valid()); EXPECT_NE(mapping.addr(), MAP_FAILED); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), kHalfPageSize); TestCookie cookie; cookie.SetUp(mapping.addr_as<uint64_t*>()); @@ -319,7 +319,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kHalfPageSize)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), kHalfPageSize); EXPECT_EQ(cookie.Observed(), cookie.Expected()); @@ -328,14 +328,14 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, 1)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), 1u); EXPECT_EQ(cookie.Observed(), cookie.Expected()); ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kPageSize - 1)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), kPageSize - 1); EXPECT_EQ(cookie.Observed(), cookie.Expected()); @@ -356,7 +356,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kHalfPageSize)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), kPageSize); + EXPECT_EQ(mapping.len(), kHalfPageSize); EXPECT_EQ(two_cookies[0].Observed(), two_cookies[0].Expected()); EXPECT_DEATH_CRASH(two_cookies[1].Check(), ""); @@ -376,7 +376,7 @@ TEST(ScopedMmapDeathTest, NotIntegralNumberOfPages) { ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kPageSize + kHalfPageSize)); EXPECT_TRUE(mapping.is_valid()); EXPECT_EQ(mapping.addr(), orig_addr); - EXPECT_EQ(mapping.len(), 2 * kPageSize); + EXPECT_EQ(mapping.len(), kPageSize + kHalfPageSize); EXPECT_EQ(two_cookies[0].Observed(), two_cookies[0].Expected()); EXPECT_EQ(two_cookies[1].Observed(), two_cookies[1].Expected()); From 5a21d038c9c9f3baa4e360b0a9bf5d6417868edf Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Thu, 28 Feb 2019 13:54:37 -0500 Subject: [PATCH 150/401] Work around libcrashpad_handler_trampoline.so ASan trunk clang problem This first landed downstream in Chromium at 7a8076717f11. Bug: chromium:936418 Change-Id: I3eea804039829163948683f014bc10dee6477fb7 Reviewed-on: https://chromium-review.googlesource.com/c/1495416 Reviewed-by: Nico Weber <thakis@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- handler/BUILD.gn | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/handler/BUILD.gn b/handler/BUILD.gn index bbd68ab1..b22ab2c4 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -14,6 +14,10 @@ import("../build/crashpad_buildconfig.gni") +if (crashpad_is_in_chromium) { + import("//build/config/sanitizers/sanitizers.gni") +} + static_library("handler") { sources = [ "crash_report_upload_thread.cc", @@ -177,7 +181,8 @@ if (crashpad_is_android) { ldflags = [ "-llog" ] - if (crashpad_is_in_chromium) { + # TODO(thakis): Remove !using_sanitizer, https://crbug.com/936418 + if (crashpad_is_in_chromium && !using_sanitizer) { no_default_deps = true } } From c8fdad4fe58fbfc92e8629bd7512316f2aaf592b Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 1 Mar 2019 17:24:21 -0500 Subject: [PATCH 151/401] Update DEPS for buildtools and GYP Point buildtools to its new location and update it to 3e50219fc450. https://chromium.googlesource.com/chromium/buildtools: 437a616be5b2 Roll doclava from Android version 6.0.0 to 8.1.0 e514b423cd41 Remove libunwind arm dependency from libc++abi d8b13809dced Build libc++abi with LIBCXXABI_SILENT_TERMINATE set dd61138d2390 Add libunwind include path to libunwind config a2cbf26d9ed3 Roll lib{cxx,cxxabi,unwind} 95d2a25d1de9 Roll gn 5478ca083b..c67646fb60 (r528993:r531988) cac097d5c2b8 Roll lib{cxx,cxxabi,unwind} f115f4786771 Revert "Roll gn 5478ca083b..c67646fb60 (r528993:r531988)" 2637e7e91152 Roll gn 5478ca083b..a0a05a85c5 (r528993:r533513) 053f96910491 Add Windows support to libc++ target a09e064635a4 Merge "Add Windows support to libc++ target." 2888931260f2 checkdeps: Add "noparent" support, similar to OWNERS files 3748a2a90871 Roll gn a0a05a85c5..ee966518c2 (r533513:r544233) 10d701fce52d Prepare for |is_posix| switch in the Fuchsia build ce837ab781da Roll lib{c++,c++abi,unwind} c81e25593ef4 [CFI] Update libc++abi to include cfi-icall fix 4c8aa3ad4fd3 Roll gn ee966518c2..b709e226c5 (r544233:r549249) e8aa02ea839e Merge "Roll gn ee966518c2..b709e226c5 (r544233:r549249)" 8febfea9bc7e Move SVN revision comments to be variables in a gni file ab7b6a7b350d Roll gn b709e226c5..76b9b6c759 (r549249:r552354) b7d53a93026d Make libc++abi C++17 ready 50bedd71e73c Roll gn 76b9b6c759..8b9e025d4d (r552354:r554932) 0b71401b977f Roll gn 8b9e025d4d..0fbf0789d9 (r554932:r555198) 292896eef97e Roll libc++abi 52c7a376..05a73941 ae5162d61ffc Remove unnecessary android_crazy_linker dependency from libc++abi c2fb17cecaf9 Correctly configure __cxa_demangle visibility a9e946f166b7 Exclude libc++abi target when use_custom_libcxx=false e7546473ac90 Move extern-C before __attribute__ declarations e0b3d0a72133 Roll gn 0fbf0789d9..ccbeab673a (r555198:r558753) 8ca403ab93e0 Merge "Move extern-C before __attribute__ declarations" 4cbff1e40ea6 Roll lib{cxx,unwind} to ToT 94288c26d2ff Revert "Roll gn 0fbf0789d9..ccbeab673a (r555198:r558753)" 893eb86b02b2 Set no_default_deps in shared libc++ builds 6f4dae280c6a Roll gn 0fbf0789d9..84176d72a4 (r555198:r564007) 5941c1b3df96 Roll gn 84176d72a4..a3bcd204a1 (r564007:r567268) 9c9fd97928dd Roll gn a3bcd204a1..7f29218b23 (r567268:r570036) f45682622e92 Remove GN from buildtools 506ae1c73670 Add gn-has-moved binary in old gn location 49b054d87c53 Remove libcpp_is_static aec56e26079f Roll to gn from gn.googlesource.com 2568b85b1fa9 Merge "Remove libcpp_is_static" 66c7d9dc3c26 Re-add .gitignore for GN a57c8cf55208 Merge "Re-add .gitignore for GN" 7876a3a2adc9 Revert "Remove libcpp_is_static" 0dd5c6f980d2 Merge "Revert "Remove libcpp_is_static"" 4ae75c1f8188 Add components/tracing in visibility for libunwind 637716e67c05 Remove libcpp_is_static 5a265b45c14c Merge "Remove libcpp_is_static" 691bfec9d73b Only set is_component_build if !is_component_build 9a90d9aaadeb Use new export_libcxxabi_from_executables variable 2dff9c9c74e9 Roll GN from "UNKNOWN" to 1413 (4cf8d15..e134e49) 13a00f110ef9 Roll lib{cxx,cxxabi,unwind} fdce2ad26b26 Roll libcxx{abi} 24ebce457874 Update clang-format binaries and scripts for all platforms da9b2941cbf6 Revert "Roll libcxx{abi} 04161ec8d7c7 Roll gn to version 1496 (0790d304) 7d88270de197 Added statically linked linux binary for clang-format b07ce09e6870 Roll lib{c++,c++abi,unwind} 5cce74c6ae2e Roll libc++ 93e021048e8a Add thomasanderson and thakis to libc++{abi} OWNERS 0e1cbc4eab68 Stop removing hide_all_but_jni_onload config from libc++ 9d61cbb94fd6 Make libc++ a shared library on Android sanitizer builds 40194ab03962 Do TODOs related to Android/libc++ 2f02e1f363b1 Don't export operator new/delete on Mac 6fbda1b24c18 Add eu-strip to buildtools/third_party/ d658e92a1fc2 Delete buildtools https://chromium.googlesource.com/chromium/src/buildtools: 6b05562fca00 [buildtools] add owners 97f503c698ae Update libcxx{abi} daac513c763a Fixes necessary for enabling libc++ on Windows 3e50219fc450 Fix mac/component/asan builds Update GYP to 8bee09f4a578. 52d9dcea6525 Add prototype of Travis config 85a2192070ba ac24c9a9501e osx 6dbd6e1ed2ad 2f9ae921f899 add copyright to .sh 2ea7773b5a97 set +x on buildbot/travis-checkout.sh 834a0592ddee fiddling with directories c3b797d883df try exporting PATH and only build ninja for now 541da5393710 try other order for sync: 39ad9f30379c see if ninja is getting pulled 007db9efe490 see if ninja is getting pulled 0afd3fc18f12 try a wrapper script 7f2941039abf readd osx d22dd9717aeb and try clang deb62526ffbb Disable some tests that fail on bots to try to get a green build 4d467626b0b9 Make Travis build only the master branch 81286d388abf infra: remove cq.cfg, which is no longer used 197c82b78bc8 Patch GYP so that building with Xcode 10 works f825c98e4bff Fix issue with missing resources in Xcode ui tests targets 6dbf304b77cb Add a copyright header to TestCmd.py 9df93ee4302e Make Visual Studio 2017 Community Edition work w/ GYP f989ef9f1c41 Use ast module instead of compiler module for parsing files f2dca32f7856 Update simple_copy.py for Python3 types ab4aca868d68 Mostly mechanical changes for Python3 support 732bde62a5eb Fix one dangling utf8 decode call needed for python 3 e22714e51525 Fixes needed for Python3 on Win32 703706c4995b src,win: add VS2019 version bd11dd1c51ef More miscellaneous fixes for Python3 compatibility 8bee09f4a578 Changes for windows and easy xml to get gyp to run under python 3 Change-Id: I7a0dc6638d275728aec2bd30c07b11492573d1e3 Reviewed-on: https://chromium-review.googlesource.com/c/1496661 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- DEPS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 0c8edf20..5b07de55 100644 --- a/DEPS +++ b/DEPS @@ -20,14 +20,14 @@ vars = { deps = { 'buildtools': - Var('chromium_git') + '/chromium/buildtools.git@' + - '6fe4a3251488f7af86d64fc25cf442e817cf6133', + Var('chromium_git') + '/chromium/src/buildtools.git@' + + '3e50219fc4503f461b2176a9976891b28d80f9ab', 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + '9518a57428ae0a7ed450c1361768e84a2a38af5a', 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + - '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f', + '8bee09f4a57807136593ddc906b0b213c21f9014', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + '737433ebade4d446643c6c07daae02a67e8decca', From 2a47ea4663ddc2ddcbde70f7dfaa9ac07f4685a0 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 6 Mar 2019 15:50:33 -0500 Subject: [PATCH 152/401] Obtain the Fuchsia SDK from the correct (updated) location Since a mac-amd64 SDK is now published in addition to linux-amd64, use it on macOS instead of repurposing linux-amd64. Many thanks to Scott Graham <scottmg@chromium.org> for helping out at https://chromium-review.googlesource.com/c/1506419. Bug: crashpad:279 Change-Id: I4f108222ec2e75dea93fe32053ab470ac7ce48b9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1503688 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- DEPS | 24 +++--- third_party/fuchsia/BUILD.gn | 137 ++++++++++++++++++++++------------- 2 files changed, 98 insertions(+), 63 deletions(-) diff --git a/DEPS b/DEPS index 5b07de55..b66addd3 100644 --- a/DEPS +++ b/DEPS @@ -89,22 +89,24 @@ deps = { 'condition': 'checkout_fuchsia and host_os == "linux"', 'dep_type': 'cipd' }, - 'crashpad/third_party/fuchsia/sdk/linux-amd64': { - # The SDK is keyed to the host system because it contains build tools. - # Currently, linux-amd64 is the only SDK published (see - # https://chrome-infra-packages.appspot.com/#/?path=fuchsia/sdk). - # As long as this is the case, use that SDK package - # even on other build hosts. - # The sysroot (containing headers and libraries) and other components are - # related to the target and should be functional with an appropriate - # toolchain that runs on the build host (fuchsia_clang, above). + 'crashpad/third_party/fuchsia/sdk/mac-amd64': { 'packages': [ { - 'package': 'fuchsia/sdk/linux-amd64', + 'package': 'fuchsia/sdk/core/mac-amd64', 'version': 'latest' }, ], - 'condition': 'checkout_fuchsia', + 'condition': 'checkout_fuchsia and host_os == "mac"', + 'dep_type': 'cipd' + }, + 'crashpad/third_party/fuchsia/sdk/linux-amd64': { + 'packages': [ + { + 'package': 'fuchsia/sdk/core/linux-amd64', + 'version': 'latest' + }, + ], + 'condition': 'checkout_fuchsia and host_os == "linux"', 'dep_type': 'cipd' }, 'crashpad/third_party/win/toolchain': { diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 1e6d94db..6965dfe0 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -26,12 +26,12 @@ if (crashpad_is_in_fuchsia) { group("zx") { public_deps = [ "//third_party/fuchsia-sdk/sdk:fdio", - "//third_party/fuchsia-sdk/sdk:zx", "//third_party/fuchsia-sdk/sdk:sysinfo", + "//third_party/fuchsia-sdk/sdk:zx", ] } } else { - sdk_path = "sdk/linux-amd64" + sdk_path = "sdk/$host_os-amd64" sdk_pkg_path = "$sdk_path/pkg" sdk_fidl_path = "$sdk_path/fidl" @@ -40,6 +40,7 @@ if (crashpad_is_in_fuchsia) { include_dirs = [ "$root_gen_dir/fidl/include", "$sdk_pkg_path/fidl/include", + "$sdk_pkg_path/fidl_base/include", "$sdk_pkg_path/zx/include", ] } @@ -70,17 +71,20 @@ if (crashpad_is_in_fuchsia) { script = "runner.py" args = [ - rebase_path("$sdk_path/tools/fidlc", root_build_dir), - "--c-header", - rebase_path(c_header, root_build_dir), - "--c-client", - rebase_path(c_client, root_build_dir), - "--tables", - rebase_path(coding_tables, root_build_dir), - "--files", - ] + [ rebase_path(fidl_source.fidl, root_build_dir) ] + rebase_path("$sdk_path/tools/fidlc", root_build_dir), + "--c-header", + rebase_path(c_header, root_build_dir), + "--c-client", + rebase_path(c_client, root_build_dir), + "--tables", + rebase_path(coding_tables, root_build_dir), + "--files", + ] + [ rebase_path(fidl_source.fidl, root_build_dir) ] - inputs = [ fidl_source.fidl, "$sdk_path/tools/fidlc" ] + inputs = [ + fidl_source.fidl, + "$sdk_path/tools/fidlc", + ] outputs = [ c_client, @@ -91,47 +95,76 @@ if (crashpad_is_in_fuchsia) { } static_library("zx") { - sources = [ - "$sdk_pkg_path/zx/channel.cpp", - "$sdk_pkg_path/zx/event.cpp", - "$sdk_pkg_path/zx/eventpair.cpp", - "$sdk_pkg_path/zx/fifo.cpp", - "$sdk_pkg_path/zx/guest.cpp", - "$sdk_pkg_path/zx/include/lib/zx/bti.h", - "$sdk_pkg_path/zx/include/lib/zx/channel.h", - "$sdk_pkg_path/zx/include/lib/zx/event.h", - "$sdk_pkg_path/zx/include/lib/zx/eventpair.h", - "$sdk_pkg_path/zx/include/lib/zx/fifo.h", - "$sdk_pkg_path/zx/include/lib/zx/guest.h", - "$sdk_pkg_path/zx/include/lib/zx/handle.h", - "$sdk_pkg_path/zx/include/lib/zx/interrupt.h", - "$sdk_pkg_path/zx/include/lib/zx/job.h", - "$sdk_pkg_path/zx/include/lib/zx/object.h", - "$sdk_pkg_path/zx/include/lib/zx/object_traits.h", - "$sdk_pkg_path/zx/include/lib/zx/pmt.h", - "$sdk_pkg_path/zx/include/lib/zx/port.h", - "$sdk_pkg_path/zx/include/lib/zx/process.h", - "$sdk_pkg_path/zx/include/lib/zx/resource.h", - "$sdk_pkg_path/zx/include/lib/zx/socket.h", - "$sdk_pkg_path/zx/include/lib/zx/task.h", - "$sdk_pkg_path/zx/include/lib/zx/thread.h", - "$sdk_pkg_path/zx/include/lib/zx/time.h", - "$sdk_pkg_path/zx/include/lib/zx/timer.h", - "$sdk_pkg_path/zx/include/lib/zx/vmar.h", - "$sdk_pkg_path/zx/include/lib/zx/vmo.h", - "$sdk_pkg_path/zx/interrupt.cpp", - "$sdk_pkg_path/zx/job.cpp", - "$sdk_pkg_path/zx/port.cpp", - "$sdk_pkg_path/zx/process.cpp", - "$sdk_pkg_path/zx/resource.cpp", - "$sdk_pkg_path/zx/socket.cpp", - "$sdk_pkg_path/zx/thread.cpp", - "$sdk_pkg_path/zx/timer.cpp", - "$sdk_pkg_path/zx/vmar.cpp", - "$sdk_pkg_path/zx/vmo.cpp", - ] + fidl_gen_sources + sources = + [ + # This is the zx library. + "$sdk_pkg_path/zx/channel.cpp", + "$sdk_pkg_path/zx/event.cpp", + "$sdk_pkg_path/zx/eventpair.cpp", + "$sdk_pkg_path/zx/fifo.cpp", + "$sdk_pkg_path/zx/guest.cpp", + "$sdk_pkg_path/zx/include/lib/zx/bti.h", + "$sdk_pkg_path/zx/include/lib/zx/channel.h", + "$sdk_pkg_path/zx/include/lib/zx/event.h", + "$sdk_pkg_path/zx/include/lib/zx/eventpair.h", + "$sdk_pkg_path/zx/include/lib/zx/fifo.h", + "$sdk_pkg_path/zx/include/lib/zx/guest.h", + "$sdk_pkg_path/zx/include/lib/zx/handle.h", + "$sdk_pkg_path/zx/include/lib/zx/interrupt.h", + "$sdk_pkg_path/zx/include/lib/zx/job.h", + "$sdk_pkg_path/zx/include/lib/zx/object.h", + "$sdk_pkg_path/zx/include/lib/zx/object_traits.h", + "$sdk_pkg_path/zx/include/lib/zx/pmt.h", + "$sdk_pkg_path/zx/include/lib/zx/port.h", + "$sdk_pkg_path/zx/include/lib/zx/process.h", + "$sdk_pkg_path/zx/include/lib/zx/resource.h", + "$sdk_pkg_path/zx/include/lib/zx/socket.h", + "$sdk_pkg_path/zx/include/lib/zx/task.h", + "$sdk_pkg_path/zx/include/lib/zx/thread.h", + "$sdk_pkg_path/zx/include/lib/zx/time.h", + "$sdk_pkg_path/zx/include/lib/zx/timer.h", + "$sdk_pkg_path/zx/include/lib/zx/vmar.h", + "$sdk_pkg_path/zx/include/lib/zx/vmo.h", + "$sdk_pkg_path/zx/interrupt.cpp", + "$sdk_pkg_path/zx/job.cpp", + "$sdk_pkg_path/zx/port.cpp", + "$sdk_pkg_path/zx/process.cpp", + "$sdk_pkg_path/zx/resource.cpp", + "$sdk_pkg_path/zx/socket.cpp", + "$sdk_pkg_path/zx/thread.cpp", + "$sdk_pkg_path/zx/timer.cpp", + "$sdk_pkg_path/zx/vmar.cpp", + "$sdk_pkg_path/zx/vmo.cpp", - deps = [ ":fuchsia.sysinfo" ] + # This is the fidl_base library. + "$sdk_pkg_path/fidl_base/builder.cpp", + "$sdk_pkg_path/fidl_base/decoding.cpp", + "$sdk_pkg_path/fidl_base/encoding.cpp", + "$sdk_pkg_path/fidl_base/envelope_frames.h", + "$sdk_pkg_path/fidl_base/formatting.cpp", + "$sdk_pkg_path/fidl_base/include/lib/fidl/coding.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/builder.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_buffer.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_builder.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_part.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/string_view.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/vector_view.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/internal.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/internal_callable_traits.h", + "$sdk_pkg_path/fidl_base/linearizing.cpp", + "$sdk_pkg_path/fidl_base/message.cpp", + "$sdk_pkg_path/fidl_base/message_buffer.cpp", + "$sdk_pkg_path/fidl_base/message_builder.cpp", + "$sdk_pkg_path/fidl_base/validating.cpp", + "$sdk_pkg_path/fidl_base/visitor.h", + "$sdk_pkg_path/fidl_base/walker.cpp", + "$sdk_pkg_path/fidl_base/walker.h", + ] + fidl_gen_sources + + deps = [ + ":fuchsia.sysinfo", + ] public_configs = [ ":zx_config" ] } From 36f9051cafcac945065b916582a8d8c7d5795e15 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 5 Mar 2019 15:55:49 -0500 Subject: [PATCH 153/401] Enable clang -Wextra-semi in POSIX/Fuchsia clang builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This completes compatibility with clang -Wextra-semi and enables that warning when building with clang for POSIX/Fuchsia. The enabling mini_chromium change depends on the compatibility changes in gtest. -Wextra-semi is only used when using mini_chromium’s build configuration. This does not affect in-Chromium builds. This updates mini_chromium to d3e46f173a22 and gtest to 8b6d3f9c4a77. Semicolon-related changes in each: mini_chromium 29c507fb618e Add -Wextra-semi to POSIX/Fuchsia Clang builds d3e46f173a22 Sync base/numerics with upstream as of 97fa6e4bdf7b gtest 56ef07a20308 Build gmock cleanly with clang -Wextra-semi a1dd07786b9a Build gmock cleanly with clang -Wextra-semi and -Wextra-semi-stmt All changes: mini_chromium 4e8b715e2aeb Partially restore VS2015 support; baseline functionality only 29c507fb618e Add -Wextra-semi to POSIX/Fuchsia Clang builds d3e46f173a22 Sync base/numerics with upstream as of 97fa6e4bdf7b gtest 4d62b5b9aef0 fix: Remove Arduino entry points 0c0ca9038245 fix: Correct *_main.cc paths adc5045cbf27 chore: Alphabetize exclude directories 23533009b872 chore: Add Windows cmake files to .gitignore 0ffa5f9779fc Merge branch 'master' into chore/fix_library_json fd1c7976aee8 Merge branch 'chore/fix_library_json' of https://github.com/ciband/googletest into chore/fix_library_json 202dcabf39fd misc: Revert formatting changes 23e693787399 misc: Reapply Arduino functions 45c58aa6f360 fix: Add Arduino setup()/loop() functions back c868da198834 Enable building as a shared library (dll) on Windows with Bazel 7c4164bf404d Fix INSTANTIATE_TEST_CASE_P with zero variadic arguments 91bfc0822855 Enable CI on Windows (appveyor) with Bazel 569fba4d742b Make internal FunctionMocker class final fdc59ffd050a Add AllOfArray matcher that verifies a value matches all member of some array/container/list/set/..., e.g: bf07131c1d0a Merge pull request #2041 from ciband:chore/fix_library_json 46b81732b634 Fixed "make dist" 5ec7f0c4a113 Merge pull request #2079 from acozzette:fix-dist 718bb65acff1 Avoid dynamic/static runtime linking (LNK4098) by properly replacing MD(d)->MT(d) in both C and CXX flags, resolves 2074 01148677a937 Merge pull request #2086 from hugolm84:fix-dynamic/static- runtime-link 1f42ae7353b3 Merge pull request #2063 from mathbunnyru:master 9318a18ccf8f Added -Wgnu-zero-variadic-macro-arguments" clang 2775733ee1e9 Update advanced.md casing in example ce29e55cfcbb Merge pull request #2090 from KellyWalker/patch-1 8e37822b4b21 Merge pull request #2063 from mathbunnyru:master acde02c635f8 Repeat #2090 e04254989d26 Merge pull request #2091 from google/gennadiycivil-patch-1 1c23efb42450 Fix README.md broken link 4f4c01d8c866 Merge pull request #2092 from Billy4195/Update_README fe519d64a6e0 fix: Add *_all.cc files to ignore list b2b24622500d fix: Add Arduino to embedded platform list 53798de93935 chore: Add PlatformIO supported platforms list 0ea2d8f8fa16 Fix stack overflow in AnyOfArray tests 67265e070677 cmake: move global project definition to beginning f89253434fd3 cmake: detect Cygwin which needs extensions to build 471f5bc433c0 Merge pull request #2098 from ciband:feat/finish_platformio_support 876bdfa565b7 Update example code in gtest.h to prefer override over virtual now 52ea4f7beaa6 Mark legacy _TEST_CASE_ macros as deprecated 50059a12b9fd Address -Wgnu-zero-variadic-macro-arguments 9df5475b8267 Test out changes with clang/OSX each PR using Travis CI 5dfcd1bc422d Update .travis.yml f80d6644d4b4 Update .travis.yml b3679d856586 Fix an invalid example of JSON report in advanced.md e28b50609e78 Merge pull request #2103 from kw-udon/fix-json-in-advanced- md 9a502a5b14b4 Merge pull request #2100 from ngie-eign/test-clang-osx- every-travis-run 47568eade6b9 fix: Correct *-all.cc file paths 48e6f1f387e6 Stop TestInfo::Run() calling a function through null pointer f4d3cdb65753 Generate a libgtest.la to help libtool managing dependencies 60cf03313da2 Set gtest version correctly for older cmake versions dda0df3b0ac6 Internal change 28a96d1834dd Fix matcher comparisons for std::reference_wrapper 4f79e316acc9 Internal changes b68ec344bfe4 Merge pull request #2101 from MaEtUgR:fix-cmake-cygwin b37574c1bfb3 Merge pull request #2107 from ciband:feat/finish_platformio_support c4ccab33aaa0 Internal Change ed2fe122f8dc Fix -Wunused-private-field issues with clang 1ded83195d93 Compile clang with `-Wall -Wshadow -Werror` 96826743ea0a Import `patch-bsd-defines` from FreeBSD ports [1] 75c3396099bf Merge pull request #2113 from knuto:pr/set_old_gtest_ver e5e846da7fda Merge pull request #2120 from ngie-eign:clang-compile-with- basic-warns-flags ea43be9d1a78 Merge pull request #2119 from ngie-eign:clang-wunused- private-field f73b2fb39efc Merge pull request #2114 from knuto:pr/libtool_support 54ec41f00018 Merge pull request #2121 from ngie-eign:add-dragonflybsd- and-kfreebsd-support d850e144710e Merge pull request #2112 from knuto:pr/fix_null_pointer a4af76cf8c13 Add `cxx_strict_flags` for clang to match FreeBSD's WARNS flags 2147806d2d5c Fix clang `-Winconsistent-missing-override` warnings 5388473acfb6 Fix clang `-Winconsistent-missing-override` warnings 1c22797cd304 Fix clang `-Wunused-parameter` warnings fcf59ca7bf63 Ignore `-Wsign-conversion` issues 9dc235b59cfd Avoid array index out of range 6d4d2f06bebc Merge pull request #2141 from dspinellis/index-fix 0e424c7594dd Update gtest-death-test to use new Fuchsia API 873e479817d3 Internal Change c374893023c9 Merge pull request #2123 from ngie-eign:clang-inconsistent- missing-override c5a792d1b685 Merge pull request #2125 from ngie-eign:clang-unused- parameter 1411d27a944d Merge pull request #2061 from samolisov:building-with- bazel-as-a-dll-on-windows 7203f37f57e4 Merge pull request #2137 from ngie-eign:clang-ignore-sign- conversion cd09534deccd Don't hardcode the filename in `CxxExceptionDeathTest.PrintsMessageForStdException` b6473fcf90a3 Merge pull request #2126 from ngie-eign:clang-add-more- strict-warnings 37ae1fc5e6be Merge pull request #2147 from ngie-eign:gtest-test-death- test-dont-hardcode-test-name d70cd4e35859 Fix grammatical error in primer.md 5154386c5f76 Merge pull request #2152 from rsinnet/patch-1 efecb0bfa687 Replace more pump'd code with variadic templates fc979623a91e Minor build system fixes 56ef07a20308 Build gmock cleanly with clang -Wextra-semi db9b85e27522 Let embedders customize GTEST_INTERNAL_DEPRECATED() a1dd07786b9a Build gmock cleanly with clang -Wextra-semi and -Wextra-semi-stmt 3dd2e841c34b Fix emission of -Wzero-as-null-pointer-constant when comparing integers 8b6d3f9c4a77 Merge pull request #2158 from CarloWood:master Bug: chromium:926235 Change-Id: I078620849c2369636d0809f0193a355aa0879cae Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1503686 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Nico Weber <thakis@chromium.org> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b66addd3..47cc28a6 100644 --- a/DEPS +++ b/DEPS @@ -24,13 +24,13 @@ deps = { '3e50219fc4503f461b2176a9976891b28d80f9ab', 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + - '9518a57428ae0a7ed450c1361768e84a2a38af5a', + '8b6d3f9c4a774bef3081195d422993323b6bb2e0', 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + '8bee09f4a57807136593ddc906b0b213c21f9014', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '737433ebade4d446643c6c07daae02a67e8decca', + 'd3e46f173a22756772f27adb43868c482581d01a', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 348022def8d59258e8ee88543d5752456996b0a0 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 6 Mar 2019 18:02:43 -0500 Subject: [PATCH 154/401] Fuchsia: Proper Fuchsia-on-macOS cross build support Update mini_chromium to df0c375531b7 df0c375531b7 Fuchsia: Proper Fuchsia-on-macOS cross build support Change-Id: I40b184ad2d61e989acf5c73b6e251a58466a801d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1505790 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 47cc28a6..4bb7d65e 100644 --- a/DEPS +++ b/DEPS @@ -30,7 +30,7 @@ deps = { '8bee09f4a57807136593ddc906b0b213c21f9014', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'd3e46f173a22756772f27adb43868c482581d01a', + 'df0c375531b7cd554e10ad757c5d2372780a1138', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From aa160f65817558424d8290e80cf67b8ce3edb2e6 Mon Sep 17 00:00:00 2001 From: Adam Barth <abarth@google.com> Date: Thu, 7 Mar 2019 09:51:05 -0800 Subject: [PATCH 155/401] [fuchsia] Update header include Previously, we included lib/fdio/util.h, but that header is being removed. The declarations we need are in lib/fdio/fdio.h now. Change-Id: I094b328766f1c67571044f85717b788eded1d142 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1508635 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Adam Barth <abarth@chromium.org> --- util/fuchsia/koid_utilities.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/fuchsia/koid_utilities.cc b/util/fuchsia/koid_utilities.cc index bb40a1c1..288f04b9 100644 --- a/util/fuchsia/koid_utilities.cc +++ b/util/fuchsia/koid_utilities.cc @@ -15,7 +15,7 @@ #include "util/fuchsia/koid_utilities.h" #include <fuchsia/sysinfo/c/fidl.h> -#include <lib/fdio/util.h> +#include <lib/fdio/fdio.h> #include <lib/zx/channel.h> #include <lib/zx/job.h> #include <lib/zx/process.h> From 1bb8ca4059d8bcc933478e02d7869dda7daa0263 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 12 Mar 2019 14:33:01 -0700 Subject: [PATCH 156/401] Silence some warnings These warnings create a lot of noise in the Android logcat Change-Id: I747a7f4cd61f4dcbb16c6dfcb3a1b4caeeaed06a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1518320 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- snapshot/minidump/thread_snapshot_minidump.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc index e77bab8b..30b2d710 100644 --- a/snapshot/minidump/thread_snapshot_minidump.cc +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -86,7 +86,6 @@ bool ThreadSnapshotMinidump::InitializeContext( } if (context_.architecture == CPUArchitecture::kCPUArchitectureX86) { - LOG(WARNING) << "Snapshot X86 context support has no unit tests."; context_memory_.resize(sizeof(CPUContextX86)); context_.x86 = reinterpret_cast<CPUContextX86*>(context_memory_.data()); const MinidumpContextX86* src = @@ -180,7 +179,6 @@ bool ThreadSnapshotMinidump::InitializeContext( context_.x86_64->dr4 = src->dr6; context_.x86_64->dr5 = src->dr7; } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM) { - LOG(WARNING) << "Snapshot ARM32 context support has no unit tests."; context_memory_.resize(sizeof(CPUContextARM)); context_.arm = reinterpret_cast<CPUContextARM*>(context_memory_.data()); const MinidumpContextARM* src = @@ -242,7 +240,6 @@ bool ThreadSnapshotMinidump::InitializeContext( context_.arm64->fpsr = src->fpsr; context_.arm64->spsr = src->cpsr; } else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPSEL) { - LOG(WARNING) << "Snapshot MIPS context support has no unit tests."; context_memory_.resize(sizeof(CPUContextMIPS)); context_.mipsel = reinterpret_cast<CPUContextMIPS*>(context_memory_.data()); const MinidumpContextMIPS* src = @@ -278,7 +275,6 @@ bool ThreadSnapshotMinidump::InitializeContext( memcpy(&context_.mipsel->fpregs, &src->fpregs, sizeof(src->fpregs)); } else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPS64EL) { - LOG(WARNING) << "Snapshot MIPS64 context support has no unit tests."; context_memory_.resize(sizeof(CPUContextMIPS64)); context_.mips64 = reinterpret_cast<CPUContextMIPS64*>(context_memory_.data()); From 8e222b90b72772c69bd14dbd09be94ce067b1b1e Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Wed, 13 Mar 2019 14:53:16 -0700 Subject: [PATCH 157/401] fix report size computation in prune condition today the attachments are not taken into account, but should on Linux and Fuchsia Bug: fuchsia:DX-1104 Tested:`fx run-test crashpad_test` for Fuchsia. Change-Id: I022331bdb09c637f40ff2ba2d711e301e211e86a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1518323 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- client/crash_report_database.cc | 3 +- client/crash_report_database.h | 5 ++ client/crash_report_database_generic.cc | 43 +++++++++++++-- client/crash_report_database_mac.mm | 8 +++ client/crash_report_database_test.cc | 68 +++++++++++++++++++++-- client/crash_report_database_win.cc | 14 ++++- client/prune_crash_reports.cc | 16 ++---- client/prune_crash_reports_test.cc | 71 +++++++++++-------------- 8 files changed, 166 insertions(+), 62 deletions(-) diff --git a/client/crash_report_database.cc b/client/crash_report_database.cc index d300a8f9..8fad1721 100644 --- a/client/crash_report_database.cc +++ b/client/crash_report_database.cc @@ -27,7 +27,8 @@ CrashReportDatabase::Report::Report() uploaded(false), last_upload_attempt_time(0), upload_attempts(0), - upload_explicitly_requested(false) {} + upload_explicitly_requested(false), + total_size(0u) {} CrashReportDatabase::NewReport::NewReport() : writer_(std::make_unique<FileWriter>()), diff --git a/client/crash_report_database.h b/client/crash_report_database.h index 1d6a9ed0..f3cc31cc 100644 --- a/client/crash_report_database.h +++ b/client/crash_report_database.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_CLIENT_CRASH_REPORT_DATABASE_H_ #define CRASHPAD_CLIENT_CRASH_REPORT_DATABASE_H_ +#include <stdint.h> #include <time.h> #include <map> @@ -98,6 +99,10 @@ class CrashReportDatabase { //! Whether this crash report was explicitly requested by user to be //! uploaded. This can be true only if report is in the 'pending' state. bool upload_explicitly_requested; + + //! The total size in bytes taken by the report, including any potential + //! attachments. + uint64_t total_size; }; //! \brief A crash report that is in the process of being written. diff --git a/client/crash_report_database_generic.cc b/client/crash_report_database_generic.cc index 8e932374..dab35a10 100644 --- a/client/crash_report_database_generic.cc +++ b/client/crash_report_database_generic.cc @@ -15,6 +15,7 @@ #include "client/crash_report_database.h" #include <stdint.h> +#include <sys/stat.h> #include <sys/types.h> #include <utility> @@ -160,6 +161,35 @@ class ScopedLockFile { DISALLOW_COPY_AND_ASSIGN(ScopedLockFile); }; +off_t GetFileSize(const base::FilePath& filepath) { + struct stat statbuf; + if (stat(filepath.value().c_str(), &statbuf) == 0) { + return statbuf.st_size; + } + PLOG(ERROR) << "stat " << filepath.value(); + return 0; +} + +void AddAttachmentSize(const base::FilePath& attachments_dir, uint64_t* size) { + // Early return if the attachment directory does not exist. + struct stat statbuf; + if (stat(attachments_dir.value().c_str(), &statbuf) != 0) { + return; + } + DirectoryReader reader; + if (!reader.Open(attachments_dir)) { + return; + } + base::FilePath attachment_filename; + DirectoryReader::Result result; + while ((result = reader.NextFile(&attachment_filename)) == + DirectoryReader::Result::kSuccess) { + const base::FilePath attachment_filepath( + attachments_dir.Append(attachment_filename)); + *size += GetFileSize(attachment_filepath); + } +} + } // namespace class CrashReportDatabaseGeneric : public CrashReportDatabase { @@ -253,7 +283,7 @@ class CrashReportDatabaseGeneric : public CrashReportDatabase { void RemoveAttachmentsByUUID(const UUID& uuid); // Reads the metadata for a report from path and returns it in report. - static bool ReadMetadata(const base::FilePath& path, Report* report); + bool ReadMetadata(const base::FilePath& path, Report* report); // Wraps ReadMetadata and removes the report from the database on failure. bool CleaningReadMetadata(const base::FilePath& path, Report* report); @@ -899,7 +929,6 @@ void CrashReportDatabaseGeneric::RemoveAttachmentsByUUID(const UUID& uuid) { LoggingRemoveDirectory(attachments_dir); } -// static bool CrashReportDatabaseGeneric::ReadMetadata(const base::FilePath& path, Report* report) { const base::FilePath metadata_path( @@ -910,7 +939,8 @@ bool CrashReportDatabaseGeneric::ReadMetadata(const base::FilePath& path, return false; } - if (!report->uuid.InitializeFromString( + UUID uuid; + if (!uuid.InitializeFromString( path.BaseName().RemoveFinalExtension().value())) { LOG(ERROR) << "Couldn't interpret report uuid"; return false; @@ -930,6 +960,12 @@ bool CrashReportDatabaseGeneric::ReadMetadata(const base::FilePath& path, return false; } + // Seed the total size with the main report size and then add the sizes of any + // potential attachments. + uint64_t total_size = GetFileSize(path); + AddAttachmentSize(AttachmentsPath(uuid), &total_size); + + report->uuid = uuid; report->upload_attempts = metadata.upload_attempts; report->last_upload_attempt_time = metadata.last_upload_attempt_time; report->creation_time = metadata.creation_time; @@ -937,6 +973,7 @@ bool CrashReportDatabaseGeneric::ReadMetadata(const base::FilePath& path, report->upload_explicitly_requested = (metadata.attributes & kAttributeUploadExplicitlyRequested) != 0; report->file_path = path; + report->total_size = total_size; return true; } diff --git a/client/crash_report_database_mac.mm b/client/crash_report_database_mac.mm index 414dd5a4..1f8fec9b 100644 --- a/client/crash_report_database_mac.mm +++ b/client/crash_report_database_mac.mm @@ -682,6 +682,14 @@ bool CrashReportDatabaseMac::ReadReportMetadataLocked( return false; } + // There are no attachments on Mac so the total size is the main report size. + struct stat statbuf; + if (stat(path.value().c_str(), &statbuf) != 0) { + PLOG(ERROR) << "stat " << path.value(); + return false; + } + report->total_size = statbuf.st_size; + return true; } diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index 2dbb4fc1..ca66bce6 100644 --- a/client/crash_report_database_test.cc +++ b/client/crash_report_database_test.cc @@ -31,8 +31,7 @@ namespace { class CrashReportDatabaseTest : public testing::Test { public: - CrashReportDatabaseTest() { - } + CrashReportDatabaseTest() {} protected: // testing::Test: @@ -41,9 +40,7 @@ class CrashReportDatabaseTest : public testing::Test { ASSERT_TRUE(db_); } - void ResetDatabase() { - db_.reset(); - } + void ResetDatabase() { db_.reset(); } CrashReportDatabase* db() { return db_.get(); } base::FilePath path() const { @@ -101,6 +98,7 @@ class CrashReportDatabaseTest : public testing::Test { EXPECT_EQ(report.last_upload_attempt_time, 0); EXPECT_EQ(report.upload_attempts, 0); EXPECT_FALSE(report.upload_explicitly_requested); + EXPECT_GE(report.total_size, 0u); } void RelocateDatabase() { @@ -835,6 +833,66 @@ TEST_F(CrashReportDatabaseTest, CleanBrokenDatabase) { } #endif // !OS_MACOSX && !OS_WIN +TEST_F(CrashReportDatabaseTest, TotalSize_MainReportOnly) { + std::unique_ptr<CrashReportDatabase::NewReport> new_report; + ASSERT_EQ(db()->PrepareNewCrashReport(&new_report), + CrashReportDatabase::kNoError); + + // Main report. + static constexpr char main_report_data[] = "dlbvandslhb"; + ASSERT_TRUE( + new_report->Writer()->Write(main_report_data, sizeof(main_report_data))); + + UUID uuid; + ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid), + CrashReportDatabase::kNoError); + + CrashReportDatabase::Report report; + ASSERT_EQ(db()->LookUpCrashReport(uuid, &report), + CrashReportDatabase::kNoError); + + EXPECT_EQ(report.total_size, sizeof(main_report_data)); +} + +TEST_F(CrashReportDatabaseTest, GetReportSize_RightSizeWithAttachments) { +#if defined(OS_MACOSX) || defined(OS_WIN) + // Attachments aren't supported on Mac and Windows yet. + return; +#else + std::unique_ptr<CrashReportDatabase::NewReport> new_report; + ASSERT_EQ(db()->PrepareNewCrashReport(&new_report), + CrashReportDatabase::kNoError); + + // Main report. + static constexpr char main_report_data[] = "dlbvandslhb"; + ASSERT_TRUE( + new_report->Writer()->Write(main_report_data, sizeof(main_report_data))); + + // First attachment. + FileWriter* attachment_1 = new_report->AddAttachment("my_attachment_1"); + ASSERT_NE(attachment_1, nullptr); + static constexpr char attachment_1_data[] = "vKDnidhvbiudshoihbvdsoiuh nhh"; + attachment_1->Write(attachment_1_data, sizeof(attachment_1_data)); + + // Second attachment. + FileWriter* attachment_2 = new_report->AddAttachment("my_attachment_2"); + ASSERT_NE(attachment_2, nullptr); + static constexpr char attachment_2_data[] = "sgvsvgusiyguysigfkhpmo-["; + attachment_2->Write(attachment_2_data, sizeof(attachment_2_data)); + + UUID uuid; + ASSERT_EQ(db()->FinishedWritingCrashReport(std::move(new_report), &uuid), + CrashReportDatabase::kNoError); + + CrashReportDatabase::Report report; + ASSERT_EQ(db()->LookUpCrashReport(uuid, &report), + CrashReportDatabase::kNoError); + EXPECT_EQ(report.total_size, + sizeof(main_report_data) + sizeof(attachment_1_data) + + sizeof(attachment_2_data)); +#endif +} + } // namespace } // namespace test } // namespace crashpad diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index 89677706..91179461 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -458,7 +458,19 @@ void Metadata::Read() { LOG(ERROR) << "invalid string table index"; return; } - reports.push_back(ReportDisk(record, report_dir_, string_table)); + ReportDisk report_disk(record, report_dir_, string_table); + + // There are no attachments on Windows so the total size is the main + // report size. + struct _stati64 statbuf; + if (_wstat64(report_disk.file_path.value().c_str(), &statbuf) == 0) { + report_disk.total_size = statbuf.st_size; + } else { + PLOG(ERROR) << "stat " + << base::UTF16ToUTF8(report_disk.file_path.value()); + } + + reports.push_back(report_disk); } } reports_.swap(reports); diff --git a/client/prune_crash_reports.cc b/client/prune_crash_reports.cc index d045eb6a..c6fa389b 100644 --- a/client/prune_crash_reports.cc +++ b/client/prune_crash_reports.cc @@ -96,19 +96,9 @@ DatabaseSizePruneCondition::~DatabaseSizePruneCondition() {} bool DatabaseSizePruneCondition::ShouldPruneReport( const CrashReportDatabase::Report& report) { -#if defined(OS_POSIX) - struct stat statbuf; - if (stat(report.file_path.value().c_str(), &statbuf) == 0) { -#elif defined(OS_WIN) - struct _stati64 statbuf; - if (_wstat64(report.file_path.value().c_str(), &statbuf) == 0) { -#else -#error "Not implemented" -#endif - // Round up fractional KB to the next 1-KB boundary. - measured_size_in_kb_ += - static_cast<size_t>((statbuf.st_size + 1023) / 1024); - } + // Round up fractional KB to the next 1-KB boundary. + measured_size_in_kb_ += + static_cast<size_t>((report.total_size + 1023) / 1024); return measured_size_in_kb_ > max_size_in_kb_; } diff --git a/client/prune_crash_reports_test.cc b/client/prune_crash_reports_test.cc index 9f5852e6..c8c43444 100644 --- a/client/prune_crash_reports_test.cc +++ b/client/prune_crash_reports_test.cc @@ -81,56 +81,49 @@ TEST(PruneCrashReports, AgeCondition) { } TEST(PruneCrashReports, SizeCondition) { - ScopedTempDir temp_dir; - CrashReportDatabase::Report report_1k; - report_1k.file_path = temp_dir.path().Append(FILE_PATH_LITERAL("file1024")); + report_1k.total_size = 1024u; CrashReportDatabase::Report report_3k; - report_3k.file_path = temp_dir.path().Append(FILE_PATH_LITERAL("file3072")); + report_3k.total_size = 1024u * 3u; + CrashReportDatabase::Report report_unset_size; { - ScopedFileHandle scoped_file_1k( - LoggingOpenFileForWrite(report_1k.file_path, - FileWriteMode::kCreateOrFail, - FilePermissions::kOwnerOnly)); - ASSERT_TRUE(scoped_file_1k.is_valid()); - - std::string string; - for (int i = 0; i < 128; ++i) - string.push_back(static_cast<char>(i)); - - for (size_t i = 0; i < 1024; i += string.size()) { - ASSERT_TRUE(LoggingWriteFile(scoped_file_1k.get(), - string.c_str(), string.length())); - } - - ScopedFileHandle scoped_file_3k( - LoggingOpenFileForWrite(report_3k.file_path, - FileWriteMode::kCreateOrFail, - FilePermissions::kOwnerOnly)); - ASSERT_TRUE(scoped_file_3k.is_valid()); - - for (size_t i = 0; i < 3072; i += string.size()) { - ASSERT_TRUE(LoggingWriteFile(scoped_file_3k.get(), - string.c_str(), string.length())); - } - } - - { - DatabaseSizePruneCondition condition(1); + DatabaseSizePruneCondition condition(/*max_size_in_kb=*/1); + // |report_1k| should not be pruned as the cumulated size is not past 1kB + // yet. EXPECT_FALSE(condition.ShouldPruneReport(report_1k)); - EXPECT_TRUE(condition.ShouldPruneReport(report_1k)); - } - - { - DatabaseSizePruneCondition condition(1); + // |report_3k| should be pruned as the cumulated size is now past 1kB. EXPECT_TRUE(condition.ShouldPruneReport(report_3k)); } { - DatabaseSizePruneCondition condition(6); + DatabaseSizePruneCondition condition(/*max_size_in_kb=*/1); + // |report_3k| should be pruned as the cumulated size is already past 1kB. + EXPECT_TRUE(condition.ShouldPruneReport(report_3k)); + } + + { + DatabaseSizePruneCondition condition(/*max_size_in_kb=*/6); + // |report_3k| should not be pruned as the cumulated size is not past 6kB + // yet. EXPECT_FALSE(condition.ShouldPruneReport(report_3k)); + // |report_3k| should not be pruned as the cumulated size is not past 6kB + // yet. EXPECT_FALSE(condition.ShouldPruneReport(report_3k)); + // |report_1k| should be pruned as the cumulated size is now past 6kB. + EXPECT_TRUE(condition.ShouldPruneReport(report_1k)); + } + + { + DatabaseSizePruneCondition condition(/*max_size_in_kb=*/0); + // |report_unset_size| should not be pruned as its size is 0, regardless of + // how many times we try to prune it. + EXPECT_FALSE(condition.ShouldPruneReport(report_unset_size)); + EXPECT_FALSE(condition.ShouldPruneReport(report_unset_size)); + EXPECT_FALSE(condition.ShouldPruneReport(report_unset_size)); + EXPECT_FALSE(condition.ShouldPruneReport(report_unset_size)); + EXPECT_FALSE(condition.ShouldPruneReport(report_unset_size)); + // |report_1k| should be pruned as the cumulated size is now past 0kB. EXPECT_TRUE(condition.ShouldPruneReport(report_1k)); } } From 8b1be541f50e75c1f32d4888bddc739022881c5e Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 19 Mar 2019 16:26:42 -0400 Subject: [PATCH 158/401] mac: Support 32-bit x86 builds Updates mini_chromium to 471390dc9c5a. 471390dc9c5a mac: Support 32-bit x86 builds % gn gen out/debug_32 --args='target_cpu="x86"' % ninja -C out/debug_32 The 10.14 SDK does not contain support to link for 32-bit x86, so with Xcode 10, it may be necessary to set the GN argument mac_sdk=10.13 (or lower) or target_sysroot to an equivalent path. It may also be necessary to coax Xcode into accepting this SDK. Change-Id: I251c870ae06e2a7d9e6d8936240f204da2f4a517 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1529224 Reviewed-by: Scott Graham <scottmg@chromium.org> Reviewed-by: Robert Sesek <rsesek@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 4bb7d65e..861d1ec0 100644 --- a/DEPS +++ b/DEPS @@ -30,7 +30,7 @@ deps = { '8bee09f4a57807136593ddc906b0b213c21f9014', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'df0c375531b7cd554e10ad757c5d2372780a1138', + '471390dc9c5a4244364c0f9c5d463ebc78083e2b', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 17d024e7df689dcc317227d6ca4d981edd026f80 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 22 Mar 2019 13:59:56 -0700 Subject: [PATCH 159/401] fuchsia: Suspend process before manipulating it This was broken by yours truly in https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1057833/, probably because I couldn't decide whether to do it in HandleException() or HandleExceptionHandles() (or possibly I'm just a dope). In any case, suspending in HandleExceptionHandles() is fine, the thread for the exception will be suspended on entry, so suspending other threads after the initial excepting thread's koid to handle lookup is OK. This avoids a bunch of logspam like: zx_thread_read_state(ZX_THREAD_STATE_GENERAL_REGS): ZX_ERR_BAD_STATE (-20) and presumably will fix non-excepting-thread stacks being completely broken? Bug: fuchsia:DX-1190 Test: run `crasher write0_mt` on device Change-Id: I029537aba2955d4f055471bf36a4e9a0f8ef2d5e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1536268 Reviewed-by: Francois Rousseau <frousseau@google.com> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- handler/fuchsia/crash_report_exception_handler.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index 85d91582..0d1ee304 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -23,6 +23,7 @@ #include "minidump/minidump_user_extension_stream_data_source.h" #include "snapshot/fuchsia/process_snapshot_fuchsia.h" #include "util/fuchsia/koid_utilities.h" +#include "util/fuchsia/scoped_task_suspend.h" namespace crashpad { @@ -96,6 +97,8 @@ bool CrashReportExceptionHandler::HandleExceptionHandles( const zx::thread& thread, const zx::unowned_port& exception_port, UUID* local_report_id) { + ScopedTaskSuspend suspend(process); + // Now that the thread has been successfully retrieved, it is possible to // correctly call zx_task_resume_from_exception() to continue exception // processing, even if something else during this function fails. From 3cc7ceaac513eee6603244ac0c03ac63e40c2445 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Mon, 25 Mar 2019 10:47:51 -0700 Subject: [PATCH 160/401] [fuchsia] do not try to suspend crashed thread * a thread blocked in an exception is technically not suspended on Fuchsia * this will take care of the spurious error message "thread failed to suspend: ZX_ERR_TIMED_OUT (-21)" introduced in https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1536268 Bug: fuchsia/ZX-3772 Tested: `fx run-test crashpad_test` on Fuchsia; verified with `fx shell crasher` no error message Change-Id: I5306732ef7c5a4f2c0fe84bc072506d57a43931e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1538558 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- util/fuchsia/scoped_task_suspend.cc | 35 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/util/fuchsia/scoped_task_suspend.cc b/util/fuchsia/scoped_task_suspend.cc index 5d9f03ec..4b4ffe74 100644 --- a/util/fuchsia/scoped_task_suspend.cc +++ b/util/fuchsia/scoped_task_suspend.cc @@ -15,6 +15,9 @@ #include "util/fuchsia/scoped_task_suspend.h" #include <lib/zx/time.h> +#include <zircon/errors.h> +#include <zircon/status.h> +#include <zircon/syscalls/object.h> #include <vector> @@ -27,16 +30,30 @@ namespace crashpad { ScopedTaskSuspend::ScopedTaskSuspend(const zx::process& process) { DCHECK_NE(process.get(), zx::process::self()->get()); - zx_status_t status = process.suspend(&suspend_token_); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_task_suspend"; - } else { - for (const auto& thread : GetThreadHandles(process)) { - zx_signals_t observed = 0u; - status = thread.wait_one( - ZX_THREAD_SUSPENDED, zx::deadline_after(zx::msec(50)), &observed); - ZX_LOG_IF(ERROR, status != ZX_OK, status) << "thread failed to suspend"; + const zx_status_t suspend_status = process.suspend(&suspend_token_); + if (suspend_status != ZX_OK) { + ZX_LOG(ERROR, suspend_status) << "zx_task_suspend"; + return; + } + + // suspend() is asynchronous so we now check that each thread is indeed + // suspended, up to some deadline. + for (const auto& thread : GetThreadHandles(process)) { + // We omit the crashed thread (blocked in an exception) as it is technically + // not suspended, cf. ZX-3772. + zx_info_thread info; + if (thread.get_info( + ZX_INFO_THREAD, &info, sizeof(info), nullptr, nullptr) == ZX_OK) { + if (info.state == ZX_THREAD_STATE_BLOCKED_EXCEPTION) { + continue; + } } + + zx_signals_t observed = 0u; + const zx_status_t wait_status = thread.wait_one( + ZX_THREAD_SUSPENDED, zx::deadline_after(zx::msec(50)), &observed); + ZX_LOG_IF(ERROR, wait_status != ZX_OK, wait_status) + << "thread failed to suspend"; } } From 75efc19dd0d5479793414549d21ba00370a52efb Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <pcc@google.com> Date: Tue, 26 Mar 2019 11:36:34 -0700 Subject: [PATCH 161/401] Make most of the tests pass on Android. - Link with -static-libstdc++ to avoid a runtime dependency on the NDK libc++. - Relax the regular expression matching the path to ar. If the path is sufficiently long then gyp will wrap the line, causing the match to fail. - The crashpad_handler binary needs to be pushed to the device, otherwise a number of tests fail or hang. Now the only tests that fail on my device are: [ FAILED ] DebugRendezvous.Self [ FAILED ] DebugRendezvous.Child [ FAILED ] ProcessReaderLinux.SelfModules [ FAILED ] ProcessReaderLinux.ChildModules Change-Id: I951a22cea5bce453d858da49a49b6a8defc1461c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1536652 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Peter Collingbourne <pcc@chromium.org> --- build/crashpad.gypi | 5 +++++ build/run_tests.py | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/build/crashpad.gypi b/build/crashpad.gypi index 166e768f..2accb5a0 100644 --- a/build/crashpad.gypi +++ b/build/crashpad.gypi @@ -35,6 +35,11 @@ }], ], }], + ['OS=="android"', { + 'ldflags': [ + '-static-libstdc++', + ], + }], ], }, } diff --git a/build/run_tests.py b/build/run_tests.py index df7d8af1..29fd3c1b 100755 --- a/build/run_tests.py +++ b/build/run_tests.py @@ -87,7 +87,7 @@ def _BinaryDirTargetOS(binary_dir): if os.path.exists(build_ninja_path): with open(build_ninja_path) as build_ninja_file: build_ninja_content = build_ninja_file.read() - match = re.search('^ar = .+-linux-android(eabi)?-ar$', + match = re.search('-linux-android(eabi)?-ar$', build_ninja_content, re.MULTILINE) if match: @@ -237,7 +237,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): # determined automatically in a GN build, following the example used for # Fuchsia. Since nothing like that exists for GYP, hard-code it for # supported tests. - test_build_artifacts = [test] + test_build_artifacts = [test, 'crashpad_handler'] test_data = ['test/test_paths_test_data_root.txt'] if test == 'crashpad_test_test': From d396fdf9d4a27dd6ed7a48dd5a0505464eb870a4 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 27 Mar 2019 17:37:33 -0700 Subject: [PATCH 162/401] Delete crashpad_dependencies.gni The file doesn't appear to be referenced anywhere and its contents are generally duplicated in test.gni and crashpad_buildconfig.gni. Change-Id: Id65a3020330a968ce3bcfb23c30e4cd0c5f808f8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1541847 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- build/crashpad_dependencies.gni | 53 --------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 build/crashpad_dependencies.gni diff --git a/build/crashpad_dependencies.gni b/build/crashpad_dependencies.gni deleted file mode 100644 index 1964facd..00000000 --- a/build/crashpad_dependencies.gni +++ /dev/null @@ -1,53 +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. - -declare_args() { - # Determines various flavors of build configuration, and which concrete - # targets to use for dependencies. Valid values are "standalone", "chromium", - # and "fuchsia". - crashpad_dependencies = "standalone" -} - -assert( - crashpad_dependencies == "chromium" || crashpad_dependencies == "fuchsia" || - crashpad_dependencies == "standalone") - -crashpad_is_in_chromium = crashpad_dependencies == "chromium" -crashpad_is_in_fuchsia = crashpad_dependencies == "fuchsia" -crashpad_is_standalone = crashpad_dependencies == "standalone" - -if (crashpad_is_in_chromium) { - crashpad_is_posix = is_posix -} else if (crashpad_is_in_fuchsia) { - import("//third_party/mini_chromium/build/is_posix.gni") - crashpad_is_posix = mini_chromium_is_posix -} else if (crashpad_is_standalone) { - import("../third_party/mini_chromium/mini_chromium/build/is_posix.gni") - crashpad_is_posix = mini_chromium_is_posix -} - -if (crashpad_is_in_chromium) { - import("//testing/test.gni") -} else { - template("test") { - executable(target_name) { - testonly = true - forward_variables_from(invoker, "*") - } - } - - set_defaults("test") { - configs = default_executable_configs - } -} From 7d5d5ff25f607e7cdc11fc6c8883c212359e7a31 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 28 Mar 2019 16:59:12 -0700 Subject: [PATCH 163/401] Avoid triggering buffer overflow detectors Writing directly into buf.tmp causes the nul-terminator to overflow into buf.crlf, which upsets some overflow detectors. Bug: crashpad:289 Change-Id: I241f1ae239ed8360ac5dfd245cb70e919ae73cd1 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1545014 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/net/http_transport_socket.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/util/net/http_transport_socket.cc b/util/net/http_transport_socket.cc index f2dd6812..4dd01b6e 100644 --- a/util/net/http_transport_socket.cc +++ b/util/net/http_transport_socket.cc @@ -394,11 +394,13 @@ bool WriteRequest(Stream* stream, // placed immediately following the used portion of buf.data, even if // buf.data is not full. - // Not snprintf because non-null terminated is desired. - int rv = sprintf( - buf.size, "%08x", base::checked_cast<unsigned int>(data_bytes)); - DCHECK_GE(rv, 0); + char tmp[9]; + int rv = snprintf(tmp, + sizeof(tmp), + "%08x", + base::checked_cast<unsigned int>(data_bytes)); DCHECK_EQ(static_cast<size_t>(rv), sizeof(buf.size)); + strncpy(buf.size, tmp, sizeof(buf.size)); DCHECK_NE(buf.size[sizeof(buf.size) - 1], '\0'); memcpy(&buf.crlf[0], kCRLFTerminator, kCRLFSize); From 94dc7eb437e22775cff2a056ae04ba3b70bfc29f Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <pcc@google.com> Date: Fri, 29 Mar 2019 15:22:11 -0700 Subject: [PATCH 164/401] Collect abort messages on Android. As of Android Q, the android_set_abort_message() function copies the abort message into a mapping with a specific name that starts with a magic number. This makes it possible for Crashpad to collect the abort message by looking for the mapping with this name in procmaps and checking for the magic number. The abort message is stored in a process annotation named "abort_message". Test: No regressions in build/run_tests.py on devices running P and Q Test: Patched into Chromium; manually verified that HWASAN crash report appears in minidump Bug: crashpad:287 Change-Id: I23c4d9e11015c84341de2d2e47e38a1eec508a36 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1544875 Commit-Queue: Peter Collingbourne <pcc@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client_linux_test.cc | 32 ++++++++ .../linux/crash_report_exception_handler.cc | 4 +- snapshot/linux/process_reader_linux.cc | 75 +++++++++++++++++++ snapshot/linux/process_reader_linux.h | 8 ++ snapshot/linux/process_reader_linux_test.cc | 33 ++++++++ snapshot/linux/process_snapshot_linux.cc | 10 +++ snapshot/linux/process_snapshot_linux.h | 16 ++-- 7 files changed, 170 insertions(+), 8 deletions(-) diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index 1f80d25f..f61ea44f 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -14,6 +14,7 @@ #include "client/crashpad_client.h" +#include <dlfcn.h> #include <stdlib.h> #include <sys/socket.h> #include <sys/syscall.h> @@ -41,6 +42,15 @@ #include "util/misc/from_pointer_cast.h" #include "util/posix/signals.h" +#if defined(OS_ANDROID) +#include <android/set_abort_message.h> +#include "dlfcn_internal.h" + +// Normally this comes from set_abort_message.h, but only at API level 21. +extern "C" void android_set_abort_message(const char* msg) + __attribute__((weak)); +#endif + namespace crashpad { namespace test { namespace { @@ -103,10 +113,26 @@ TEST(CrashpadClient, SimulateCrash) { constexpr char kTestAnnotationName[] = "name_of_annotation"; constexpr char kTestAnnotationValue[] = "value_of_annotation"; +#if defined(OS_ANDROID) +constexpr char kTestAbortMessage[] = "test abort message"; +#endif + void ValidateDump(const CrashReportDatabase::UploadReport* report) { ProcessSnapshotMinidump minidump_snapshot; ASSERT_TRUE(minidump_snapshot.Initialize(report->Reader())); +#if defined(OS_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. + if (crashpad::internal::Dlsym(RTLD_DEFAULT, "android_fdsan_close_with_tag")) { + const auto& annotations = minidump_snapshot.AnnotationsSimpleMap(); + auto abort_message = annotations.find("abort_message"); + ASSERT_NE(annotations.end(), abort_message); + EXPECT_EQ(kTestAbortMessage, abort_message->second); + } +#endif + for (const ModuleSnapshot* module : minidump_snapshot.Modules()) { for (const AnnotationSnapshot& annotation : module->AnnotationObjects()) { if (static_cast<Annotation::Type>(annotation.type) != @@ -153,6 +179,12 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerAtCrashChild) { return EXIT_FAILURE; } +#if defined(OS_ANDROID) + if (android_set_abort_message) { + android_set_abort_message(kTestAbortMessage); + } +#endif + __builtin_trap(); NOTREACHED(); diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 71a7009b..910b2884 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -107,7 +107,9 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( } process_snapshot.SetClientID(client_id); - process_snapshot.SetAnnotationsSimpleMap(*process_annotations_); + for (auto& p : *process_annotations_) { + process_snapshot.AddAnnotation(p.first, p.second); + } std::unique_ptr<CrashReportDatabase::NewReport> new_report; CrashReportDatabase::OperationStatus database_status = diff --git a/snapshot/linux/process_reader_linux.cc b/snapshot/linux/process_reader_linux.cc index c1d6c40f..b96abfe7 100644 --- a/snapshot/linux/process_reader_linux.cc +++ b/snapshot/linux/process_reader_linux.cc @@ -280,6 +280,81 @@ const std::vector<ProcessReaderLinux::Module>& ProcessReaderLinux::Modules() { return modules_; } +void ProcessReaderLinux::InitializeAbortMessage() { +#if defined(OS_ANDROID) + const MemoryMap::Mapping* mapping = + memory_map_.FindMappingWithName("[anon:abort message]"); + if (!mapping) { + return; + } + + if (is_64_bit_) { + ReadAbortMessage<true>(mapping); + } else { + ReadAbortMessage<false>(mapping); + } +#endif +} + +#if defined(OS_ANDROID) + +// These structure definitions and the magic numbers below were copied from +// bionic/libc/bionic/android_set_abort_message.cpp + +template <bool is64Bit> +struct abort_msg_t { + uint32_t size; + char msg[0]; +}; + +template <> +struct abort_msg_t<true> { + uint64_t size; + char msg[0]; +}; + +template <bool is64Bit> +struct magic_abort_msg_t { + uint64_t magic1; + uint64_t magic2; + abort_msg_t<is64Bit> msg; +}; + +template <bool is64Bit> +void ProcessReaderLinux::ReadAbortMessage(const MemoryMap::Mapping* mapping) { + magic_abort_msg_t<is64Bit> header; + if (!Memory()->Read( + mapping->range.Base(), sizeof(magic_abort_msg_t<is64Bit>), &header)) { + return; + } + + size_t size = header.msg.size - sizeof(magic_abort_msg_t<is64Bit>) - 1; + if (header.magic1 != 0xb18e40886ac388f0ULL || + header.magic2 != 0xc6dfba755a1de0b5ULL || + mapping->range.Size() < + offsetof(magic_abort_msg_t<is64Bit>, msg.msg) + size) { + return; + } + + abort_message_.resize(size); + if (!Memory()->Read( + mapping->range.Base() + offsetof(magic_abort_msg_t<is64Bit>, msg.msg), + size, + &abort_message_[0])) { + abort_message_.clear(); + } +} + +#endif // OS_ANDROID + +const std::string& ProcessReaderLinux::AbortMessage() { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (abort_message_.empty()) { + InitializeAbortMessage(); + } + return abort_message_; +} + void ProcessReaderLinux::InitializeThreads() { DCHECK(threads_.empty()); initialized_threads_ = true; diff --git a/snapshot/linux/process_reader_linux.h b/snapshot/linux/process_reader_linux.h index 1b30f53e..258e102a 100644 --- a/snapshot/linux/process_reader_linux.h +++ b/snapshot/linux/process_reader_linux.h @@ -153,15 +153,23 @@ class ProcessReaderLinux { //! `0`) corresponds to the main executable. const std::vector<Module>& Modules(); + //! \return On Android, the abort message that was passed to + //! android_set_abort_message(). This is only available on Q or later. + const std::string& AbortMessage(); + private: void InitializeThreads(); void InitializeModules(); + void InitializeAbortMessage(); + template <bool Is64Bit> + void ReadAbortMessage(const MemoryMap::Mapping* mapping); PtraceConnection* connection_; // weak ProcessInfo process_info_; MemoryMap memory_map_; std::vector<Thread> threads_; std::vector<Module> modules_; + std::string abort_message_; std::vector<std::unique_ptr<ElfImageReader>> elf_readers_; bool is_64_bit_; bool initialized_threads_; diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index e2e5566c..e25b8023 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -38,6 +38,7 @@ #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" +#include "test/gtest_disabled.h" #include "test/linux/fake_ptrace_connection.h" #include "test/linux/get_tls.h" #include "test/multiprocess.h" @@ -53,6 +54,12 @@ #if defined(OS_ANDROID) #include <android/api-level.h> +#include <android/set_abort_message.h> +#include "dlfcn_internal.h" + +// Normally this comes from set_abort_message.h, but only at API level 21. +extern "C" void android_set_abort_message(const char* msg) + __attribute__((weak)); #endif namespace crashpad { @@ -86,6 +93,8 @@ TEST(ProcessReaderLinux, SelfBasic) { sizeof(kTestMemory), &buffer)); EXPECT_STREQ(kTestMemory, buffer); + + EXPECT_EQ("", process_reader.AbortMessage()); } constexpr char kTestMemory[] = "Read me from another process"; @@ -778,6 +787,30 @@ TEST(ProcessReaderLinux, ChildModules) { test.Run(); } +#if defined(OS_ANDROID) +const char kTestAbortMessage[] = "test abort message"; + +TEST(ProcessReaderLinux, AbortMessage) { + // This 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. + if (!crashpad::internal::Dlsym(RTLD_DEFAULT, + "android_fdsan_close_with_tag")) { + DISABLED_TEST(); + } + + android_set_abort_message(kTestAbortMessage); + + FakePtraceConnection connection; + connection.Initialize(getpid()); + + ProcessReaderLinux process_reader; + ASSERT_TRUE(process_reader.Initialize(&connection)); + + EXPECT_EQ(kTestAbortMessage, process_reader.AbortMessage()); +} +#endif + } // namespace } // namespace test } // namespace crashpad diff --git a/snapshot/linux/process_snapshot_linux.cc b/snapshot/linux/process_snapshot_linux.cc index 041653a3..4141b2f4 100644 --- a/snapshot/linux/process_snapshot_linux.cc +++ b/snapshot/linux/process_snapshot_linux.cc @@ -43,6 +43,7 @@ bool ProcessSnapshotLinux::Initialize(PtraceConnection* connection) { InitializeThreads(); InitializeModules(); + InitializeAnnotations(); INITIALIZATION_STATE_SET_VALID(initialized_); return true; @@ -265,4 +266,13 @@ void ProcessSnapshotLinux::InitializeModules() { } } +void ProcessSnapshotLinux::InitializeAnnotations() { +#if defined(OS_ANDROID) + const std::string& abort_message = process_reader_.AbortMessage(); + if (!abort_message.empty()) { + annotations_simple_map_["abort_message"] = abort_message; + } +#endif +} + } // namespace crashpad diff --git a/snapshot/linux/process_snapshot_linux.h b/snapshot/linux/process_snapshot_linux.h index 236926d6..84bd226a 100644 --- a/snapshot/linux/process_snapshot_linux.h +++ b/snapshot/linux/process_snapshot_linux.h @@ -78,15 +78,16 @@ class ProcessSnapshotLinux final : public ProcessSnapshot { //! ClientID() will return an identifier consisting entirely of zeroes. void SetClientID(const UUID& client_id) { client_id_ = client_id; } - //! \brief Sets the value to be returned by AnnotationsSimpleMap(). + //! \brief Add an annotation to be returned by AnnotationsSimpleMap(). //! - //! All process annotations are under the control of the snapshot + //! Most process annotations are under the control of the snapshot //! producer, which may call this method to establish these annotations. - //! Contrast this with module annotations, which are under the control of the - //! process being snapshotted. - void SetAnnotationsSimpleMap( - const std::map<std::string, std::string>& annotations_simple_map) { - annotations_simple_map_ = annotations_simple_map; + //! On Android Q or later, the process snapshot may add an "abort_message" + //! annotation, which will contain the abort message passed to the + //! android_set_abort_message() function. Contrast this with module + //! annotations, which are under the control of the process being snapshotted. + void AddAnnotation(const std::string& key, const std::string& value) { + annotations_simple_map_[key] = value; } //! \brief Returns options from CrashpadInfo structures found in modules in @@ -120,6 +121,7 @@ class ProcessSnapshotLinux final : public ProcessSnapshot { private: void InitializeThreads(); void InitializeModules(); + void InitializeAnnotations(); std::map<std::string, std::string> annotations_simple_map_; timeval snapshot_time_; From 439f50fb11c86c59e1707bc8f006608b8f1df457 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <pcc@chromium.org> Date: Sat, 30 Mar 2019 00:39:49 +0000 Subject: [PATCH 165/401] Revert "Work around libcrashpad_handler_trampoline.so ASan trunk clang problem" This reverts commit 5a21d038c9c9f3baa4e360b0a9bf5d6417868edf. Reason for revert: Toolchain bug has now been fixed. Original change's description: > Work around libcrashpad_handler_trampoline.so ASan trunk clang problem > > This first landed downstream in Chromium at 7a8076717f11. > > Bug: chromium:936418 > Change-Id: I3eea804039829163948683f014bc10dee6477fb7 > Reviewed-on: https://chromium-review.googlesource.com/c/1495416 > Reviewed-by: Nico Weber <thakis@chromium.org> > Commit-Queue: Mark Mentovai <mark@chromium.org> TBR=thakis@chromium.org,mark@chromium.org # Not skipping CQ checks because original CL landed > 1 day ago. Bug: chromium:936418 Change-Id: I17d40865b64805ffdc1fb5e71e67fee1856c03b7 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1546813 Reviewed-by: Nico Weber <thakis@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org> --- handler/BUILD.gn | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/handler/BUILD.gn b/handler/BUILD.gn index b22ab2c4..bbd68ab1 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -14,10 +14,6 @@ import("../build/crashpad_buildconfig.gni") -if (crashpad_is_in_chromium) { - import("//build/config/sanitizers/sanitizers.gni") -} - static_library("handler") { sources = [ "crash_report_upload_thread.cc", @@ -181,8 +177,7 @@ if (crashpad_is_android) { ldflags = [ "-llog" ] - # TODO(thakis): Remove !using_sanitizer, https://crbug.com/936418 - if (crashpad_is_in_chromium && !using_sanitizer) { + if (crashpad_is_in_chromium) { no_default_deps = true } } From b0373799bac78187e1ef932d2e150c19bac83141 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Mon, 1 Apr 2019 13:38:26 -0700 Subject: [PATCH 166/401] [fuchsia] fix module names for executables and loadable modules On Fuchsia, executables and loadable modules don't have a name at build time so we use "<_>" as module name to index their symbols on the crash server. We need to use the same dummy value at run time. Bug: fuchsia/DX-1193 Tested: `fx run-test crashpad_test` Change-Id: Ie926a6d26cb52679ccfac767db098c9fbfd21dd8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1548230 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/fuchsia/process_reader_fuchsia.cc | 52 ++++++++++++------- .../fuchsia/process_reader_fuchsia_test.cc | 14 +++++ 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/snapshot/fuchsia/process_reader_fuchsia.cc b/snapshot/fuchsia/process_reader_fuchsia.cc index 0c8b6ca7..e3eaf752 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.cc +++ b/snapshot/fuchsia/process_reader_fuchsia.cc @@ -130,19 +130,6 @@ void ProcessReaderFuchsia::InitializeModules() { // retrieves (some of) the data into internal structures. It may be worth // trying to refactor/upstream some of this into Fuchsia. - std::string app_name; - { - char name[ZX_MAX_NAME_LEN]; - zx_status_t status = - process_->get_property(ZX_PROP_NAME, name, sizeof(name)); - if (status != ZX_OK) { - LOG(ERROR) << "zx_object_get_property ZX_PROP_NAME"; - return; - } - - app_name = name; - } - // Starting from the ld.so's _dl_debug_addr, read the link_map structure and // walk the list to fill out modules_. @@ -204,19 +191,44 @@ void ProcessReaderFuchsia::InitializeModules() { LOG(ERROR) << "ReadCString name"; } - // The vDSO is libzircon.so, but it's not actually loaded normally, it's - // injected by the kernel, so doesn't have a normal name. When dump_syms is - // run on libzircon.so, it uses that file name, and in order for the crash - // server to match symbols both the debug id and the name of the binary have - // to match. So, map from "<vDSO>" to "libzircon.so" so that symbol - // resolution works correctly. + // Debug symbols are indexed by module name x build-id on the crash server. + // The module name in the indexed Breakpad files is set at build time. So + // Crashpad needs to use the same module name at run time for symbol + // resolution to work properly. + // + // TODO(fuchsia/DX-1234): once Crashpad switches to elf-search, the + // following overwrites won't be necessary as only shared libraries will + // have a soname at runtime, just like at build time. + // + // * For shared libraries, the soname is used as module name at build time, + // which is the dsoname here except for libzircon.so (because it is + // injected by the kernel, its load name is "<vDSO>" and Crashpad needs to + // replace it for symbol resolution to work properly). if (dsoname == "<vDSO>") { dsoname = "libzircon.so"; } + // * For executables and loadable modules, the dummy value "<_>" is used as + // module name at build time. This is because executable and loadable + // modules don't have a name on Fuchsia. So we need to use the same dummy + // value at build and run times. + // Most executables have an empty dsoname. Loadable modules (and some rare + // executables) have a non-empty dsoname starting with a specific prefix, + // which Crashpas can use to identify loadable modules and clear the + // dsoname for them. + static constexpr const char kLoadableModuleLoadNamePrefix[] = "<VMO#"; + // Pre-C++ 20 std::basic_string::starts_with + if (dsoname.compare(0, + strlen(kLoadableModuleLoadNamePrefix), + kLoadableModuleLoadNamePrefix) == 0) { + dsoname = ""; + } Module module; if (dsoname.empty()) { - module.name = app_name; + // This value must be kept in sync with what is used at build time to + // index symbols for executables and loadable modules. + // See fuchsia/DX-1193 for more details. + module.name = "<_>"; module.type = ModuleSnapshot::kModuleTypeExecutable; } else { module.name = dsoname; diff --git a/snapshot/fuchsia/process_reader_fuchsia_test.cc b/snapshot/fuchsia/process_reader_fuchsia_test.cc index 83385a85..369ec9a3 100644 --- a/snapshot/fuchsia/process_reader_fuchsia_test.cc +++ b/snapshot/fuchsia/process_reader_fuchsia_test.cc @@ -41,11 +41,25 @@ TEST(ProcessReaderFuchsia, SelfBasic) { EXPECT_STREQ(kTestMemory, buffer); const auto& modules = process_reader.Modules(); + // The process should have at least one module, the executable, and then some + // shared libraries, no loadable modules. EXPECT_GT(modules.size(), 0u); + size_t num_executables = 0u; + size_t num_shared_libraries = 0u; for (const auto& module : modules) { EXPECT_FALSE(module.name.empty()); EXPECT_NE(module.type, ModuleSnapshot::kModuleTypeUnknown); + + if (module.type == ModuleSnapshot::kModuleTypeExecutable) { + EXPECT_EQ(module.name, "<_>"); + num_executables++; + } else if (module.type == ModuleSnapshot::kModuleTypeSharedLibrary) { + EXPECT_NE(module.name, "<_>"); + num_shared_libraries++; + } } + EXPECT_EQ(num_executables, 1u); + EXPECT_EQ(num_shared_libraries, modules.size() - num_executables); const auto& threads = process_reader.Threads(); EXPECT_GT(threads.size(), 0u); From 0730f0c60c40452f39436db6bf3a5f8e1e885adc Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Fri, 5 Apr 2019 15:45:15 -0700 Subject: [PATCH 167/401] [fuchsia] rename gn group to fuchsia now that we import fuchsia-sysinfo and fdio, this isn't really just zx anymore Change-Id: Ic42359ce3d230e214ebdbbefb880ccb021434a0f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1555533 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- client/BUILD.gn | 4 +++- handler/BUILD.gn | 2 +- test/BUILD.gn | 2 +- third_party/fuchsia/BUILD.gn | 19 +++++++++++++------ third_party/gtest/BUILD.gn | 2 +- util/BUILD.gn | 2 +- 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/client/BUILD.gn b/client/BUILD.gn index f23185de..56312af0 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -88,7 +88,9 @@ static_library("client") { } if (crashpad_is_fuchsia) { - deps = [ "../third_party/fuchsia:zx" ] + deps = [ + "../third_party/fuchsia", + ] if (crashpad_is_in_fuchsia) { deps += [ "//zircon/public/lib/fdio" ] } diff --git a/handler/BUILD.gn b/handler/BUILD.gn index bbd68ab1..67c77e5f 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -84,7 +84,7 @@ static_library("handler") { } if (crashpad_is_fuchsia) { - deps += [ "../third_party/fuchsia:zx" ] + deps += [ "../third_party/fuchsia" ] } } diff --git a/test/BUILD.gn b/test/BUILD.gn index bded2c60..fb99bce6 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -134,7 +134,7 @@ static_library("test") { if (crashpad_is_fuchsia) { public_deps = [ - "../third_party/fuchsia:zx", + "../third_party/fuchsia", ] if (crashpad_is_in_fuchsia) { deps += [ "//zircon/public/lib/fdio" ] diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 6965dfe0..294d08d6 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -15,7 +15,7 @@ import("../../build/crashpad_buildconfig.gni") if (crashpad_is_in_fuchsia) { - group("zx") { + group("fuchsia") { public_deps = [ "//zircon/public/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c", "//zircon/public/lib/fdio", @@ -23,7 +23,7 @@ if (crashpad_is_in_fuchsia) { ] } } else if (crashpad_is_in_chromium) { - group("zx") { + group("fuchsia") { public_deps = [ "//third_party/fuchsia-sdk/sdk:fdio", "//third_party/fuchsia-sdk/sdk:sysinfo", @@ -36,12 +36,16 @@ if (crashpad_is_in_fuchsia) { sdk_fidl_path = "$sdk_path/fidl" config("zx_config") { - visibility = [ ":zx" ] + visibility = [ ":fuchsia" ] + include_dirs = [ "$sdk_pkg_path/zx/include" ] + } + + config("fidl_config") { + visibility = [ ":fuchsia" ] include_dirs = [ "$root_gen_dir/fidl/include", "$sdk_pkg_path/fidl/include", "$sdk_pkg_path/fidl_base/include", - "$sdk_pkg_path/zx/include", ] } @@ -94,7 +98,7 @@ if (crashpad_is_in_fuchsia) { } } - static_library("zx") { + static_library("fuchsia") { sources = [ # This is the zx library. @@ -166,6 +170,9 @@ if (crashpad_is_in_fuchsia) { ":fuchsia.sysinfo", ] - public_configs = [ ":zx_config" ] + public_configs = [ + ":fidl_config", + ":zx_config", + ] } } diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index e124b9e7..c2058e23 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -97,7 +97,7 @@ if (crashpad_is_in_chromium) { configs += [ ":gtest_private_config" ] if (crashpad_is_fuchsia) { deps = [ - "../fuchsia:zx", + "../fuchsia", ] } } diff --git a/util/BUILD.gn b/util/BUILD.gn index 41a74d63..f571b863 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -467,7 +467,7 @@ static_library("util") { } if (crashpad_is_fuchsia) { - public_deps += [ "../third_party/fuchsia:zx" ] + public_deps += [ "../third_party/fuchsia" ] } } From c8dc08b719b711ea6d8719ac7727a6c74ea4d1f3 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Fri, 5 Apr 2019 18:13:00 -0700 Subject: [PATCH 168/401] [fuchsia] clean up third_party/fuchsia/BUILD.gn Change-Id: I5c5f03ea5882592008d11e2819962e8781954ca2 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1555833 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- third_party/fuchsia/BUILD.gn | 40 +++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 294d08d6..f712af24 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -33,17 +33,18 @@ if (crashpad_is_in_fuchsia) { } else { sdk_path = "sdk/$host_os-amd64" sdk_pkg_path = "$sdk_path/pkg" - sdk_fidl_path = "$sdk_path/fidl" + sdk_fidl_sources_path = "$sdk_path/fidl" config("zx_config") { visibility = [ ":fuchsia" ] include_dirs = [ "$sdk_pkg_path/zx/include" ] } + fidl_root_gen_dir = "$root_gen_dir/fidl/include" config("fidl_config") { visibility = [ ":fuchsia" ] include_dirs = [ - "$root_gen_dir/fidl/include", + fidl_root_gen_dir, "$sdk_pkg_path/fidl/include", "$sdk_pkg_path/fidl_base/include", ] @@ -51,7 +52,7 @@ if (crashpad_is_in_fuchsia) { fidl_sources = [ { - fidl = "$sdk_fidl_path/fuchsia.sysinfo/sysinfo.fidl" + fidl = "$sdk_fidl_sources_path/fuchsia.sysinfo/sysinfo.fidl" header_stem = "fuchsia/sysinfo" library_name = "fuchsia.sysinfo" }, @@ -60,8 +61,9 @@ if (crashpad_is_in_fuchsia) { fidl_gen_sources = [] foreach(fidl_source, fidl_sources) { fidl_stem = "$target_gen_dir/fidl/${fidl_source.library_name}" - c_header = "$root_gen_dir/fidl/include/${fidl_source.header_stem}/c/fidl.h" - c_client = "$fidl_stem/client.cc" + c_stem = "$fidl_root_gen_dir/${fidl_source.header_stem}/c" + c_header = "$c_stem/fidl.h" + c_client = "$c_stem/client.cc" coding_tables = "$fidl_stem/tables.cc" fidl_gen_sources += [ @@ -69,25 +71,29 @@ if (crashpad_is_in_fuchsia) { coding_tables, ] - action(fidl_source.library_name) { + # Compiles the .fidl file and generates the C bindings. + action("fidlc_${fidl_source.library_name}") { visibility = [ ":*" ] script = "runner.py" args = [ - rebase_path("$sdk_path/tools/fidlc", root_build_dir), - "--c-header", - rebase_path(c_header, root_build_dir), - "--c-client", - rebase_path(c_client, root_build_dir), - "--tables", - rebase_path(coding_tables, root_build_dir), - "--files", - ] + [ rebase_path(fidl_source.fidl, root_build_dir) ] + rebase_path("$sdk_path/tools/fidlc", root_build_dir), + "--c-header", + rebase_path(c_header, root_build_dir), + "--c-client", + rebase_path(c_client, root_build_dir), + "--tables", + rebase_path(coding_tables, root_build_dir), + "--name", + fidl_source.library_name, + "--files", + rebase_path(fidl_source.fidl, root_build_dir), + ] inputs = [ - fidl_source.fidl, "$sdk_path/tools/fidlc", + fidl_source.fidl, ] outputs = [ @@ -167,7 +173,7 @@ if (crashpad_is_in_fuchsia) { ] + fidl_gen_sources deps = [ - ":fuchsia.sysinfo", + ":fidlc_fuchsia.sysinfo", ] public_configs = [ From 71d2291f4eb9d88777d60f24526754f3950ac01a Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Mon, 8 Apr 2019 14:25:44 -0700 Subject: [PATCH 169/401] [windows] stop PLOGing report path if stat fails apparently we're attempting to log to a C++ out-stream during process exit, and that is causing the run-time to try to do a character-set conversion, requiring it to look up some run-time locale state which has presumably already been torn-down Bug: chromium:948588 Change-Id: I9431dafd0aaaa8827faf3b24985873733b431e22 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1558812 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- client/crash_report_database_win.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/crash_report_database_win.cc b/client/crash_report_database_win.cc index 91179461..15137d0c 100644 --- a/client/crash_report_database_win.cc +++ b/client/crash_report_database_win.cc @@ -466,8 +466,7 @@ void Metadata::Read() { if (_wstat64(report_disk.file_path.value().c_str(), &statbuf) == 0) { report_disk.total_size = statbuf.st_size; } else { - PLOG(ERROR) << "stat " - << base::UTF16ToUTF8(report_disk.file_path.value()); + LOG(ERROR) << "failed to stat report"; } reports.push_back(report_disk); From ae431a1ae546d18ff226b37d447dca0e18b96afa Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 8 Apr 2019 15:29:04 -0700 Subject: [PATCH 170/401] linux: Disable DumpWithoutCrash() if Crashpad isn't initialized When sampling has disabled crash reporting for WebView, no signal handler is initialized, causing later calls to DumpWithoutCrash() to crash. Bug: 949295 Change-Id: Ib93986f81bc83404ac9f4d8f40fb34e54f1b3bec Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1558817 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client_linux.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index fe5798a5..4b9c1752 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -377,7 +377,10 @@ bool CrashpadClient::StartHandlerForClient( // static void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) { - DCHECK(g_crash_handler); + if (!g_crash_handler) { + DLOG(ERROR) << "Crashpad isn't enabled"; + return; + } #if defined(ARCH_CPU_ARMEL) memset(context->uc_regspace, 0, sizeof(context->uc_regspace)); From cc0c2f90df7e1abbd37efb86563a5458fcc305ea Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 8 Apr 2019 17:28:18 -0700 Subject: [PATCH 171/401] Add lss to third_party and use sys_getpid() More syscalls to come. Bug: crashpad:265 Change-Id: Ib139e638b0356426f922650249632132fd613f6f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1540403 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- DEPS | 3 +++ client/BUILD.gn | 10 +++++++++- client/client.gyp | 1 + client/crashpad_client_linux.cc | 3 ++- third_party/lss/BUILD.gn | 31 +++++++++++++++++++++++++++++++ third_party/lss/README.crashpad | 16 ++++++++++++++++ third_party/lss/lss.gyp | 27 +++++++++++++++++++++++++++ third_party/lss/lss.h | 26 ++++++++++++++++++++++++++ 8 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 third_party/lss/BUILD.gn create mode 100644 third_party/lss/README.crashpad create mode 100644 third_party/lss/lss.gyp create mode 100644 third_party/lss/lss.h diff --git a/DEPS b/DEPS index 861d1ec0..7f08b885 100644 --- a/DEPS +++ b/DEPS @@ -28,6 +28,9 @@ deps = { 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + '8bee09f4a57807136593ddc906b0b213c21f9014', + 'crashpad/third_party/lss/lss': + Var('chromium_git') + '/linux-syscall-support.git@' + + '8048ece6c16c91acfe0d36d1d3cc0890ab6e945c', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + '471390dc9c5a4244364c0f9c5d463ebc78083e2b', diff --git a/client/BUILD.gn b/client/BUILD.gn index 56312af0..bfe03320 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -82,13 +82,21 @@ static_library("client") { "../util", ] + deps = [] + if (crashpad_is_win) { libs = [ "rpcrt4.lib" ] cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union } + if (crashpad_is_linux || crashpad_is_android) { + deps += [ + "../third_party/lss", + ] + } + if (crashpad_is_fuchsia) { - deps = [ + deps += [ "../third_party/fuchsia", ] if (crashpad_is_in_fuchsia) { diff --git a/client/client.gyp b/client/client.gyp index a23d0c86..dcb2d0eb 100644 --- a/client/client.gyp +++ b/client/client.gyp @@ -23,6 +23,7 @@ 'dependencies': [ '../compat/compat.gyp:crashpad_compat', '../third_party/mini_chromium/mini_chromium.gyp:base', + '../third_party/lss/lss.gyp:lss', '../util/util.gyp:crashpad_util', ], 'include_dirs': [ diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 4b9c1752..b72980c1 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -25,6 +25,7 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" #include "client/client_argv_handling.h" +#include "third_party/lss/lss.h" #include "util/file/file_io.h" #include "util/linux/exception_handler_client.h" #include "util/linux/exception_information.h" @@ -149,7 +150,7 @@ class LaunchAtCrashHandler { context); exception_information_.thread_id = syscall(SYS_gettid); - ScopedPrSetPtracer set_ptracer(getpid(), /* may_log= */ false); + ScopedPrSetPtracer set_ptracer(sys_getpid(), /* may_log= */ false); ScopedPrSetDumpable set_dumpable(/* may_log= */ false); pid_t pid = fork(); diff --git a/third_party/lss/BUILD.gn b/third_party/lss/BUILD.gn new file mode 100644 index 00000000..1e0bd2bf --- /dev/null +++ b/third_party/lss/BUILD.gn @@ -0,0 +1,31 @@ +# 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. + +import("../../build/crashpad_buildconfig.gni") + +config("lss_config") { + if (crashpad_is_in_chromium) { + defines = [ "CRASHPAD_LSS_SOURCE_EXTERNAL" ] + } else { + defines = [ "CRASHPAD_LSS_SOURCE_EMBEDDED" ] + } +} + +source_set("lss") { + public_configs = [ ":lss_config" ] + + sources = [ + "lss.h", + ] +} diff --git a/third_party/lss/README.crashpad b/third_party/lss/README.crashpad new file mode 100644 index 00000000..c036ae0f --- /dev/null +++ b/third_party/lss/README.crashpad @@ -0,0 +1,16 @@ +Name: linux-syscall-support +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 +Security Critical: yes + +Description: +Every so often, projects need to directly embed Linux system calls instead of +calling the implementations in the system runtime library. This project +provides a header file that can be included into your application whenever you +need to make direct system calls. + +Local Modifications: +None. diff --git a/third_party/lss/lss.gyp b/third_party/lss/lss.gyp new file mode 100644 index 00000000..63b9b3ae --- /dev/null +++ b/third_party/lss/lss.gyp @@ -0,0 +1,27 @@ +# 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. + +{ + 'targets': [ + { + 'target_name': 'lss', + 'type': 'none', + 'sources': [ 'lss.h' ], + 'direct_dependent_settings': { + # gyp is only used in circumstances when the embedded lss is used. + 'defines': [ 'CRASHPAD_LSS_SOURCE_EMBEDDED' ] + }, + } + ] +} diff --git a/third_party/lss/lss.h b/third_party/lss/lss.h new file mode 100644 index 00000000..11209ff8 --- /dev/null +++ b/third_party/lss/lss.h @@ -0,0 +1,26 @@ +// 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_THIRD_PARTY_LSS_LSS_H_ +#define CRASHPAD_THIRD_PARTY_LSS_LSS_H_ + +#if defined(CRASHPAD_LSS_SOURCE_EXTERNAL) +#include "third_party/lss/linux_syscall_support.h" +#elif defined(CRASHPAD_LSS_SOURCE_EMBEDDED) +#include "third_party/lss/lss/linux_syscall_support.h" +#else +#error Unknown lss source +#endif + +#endif // CRASHPAD_THIRD_PARTY_LSS_LSS_H_ From 5a94b550008db2d6ea0b522b2b5f6a598f8419e5 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 9 Apr 2019 09:37:52 -0700 Subject: [PATCH 172/401] [lss] add third_party/lss/lss to .gitignore ug: crashpad:265 Change-Id: I81d5c2dd734b8daeacaee37f3f2314bb9e473f53 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1559309 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 982a95e7..90038f1d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ /third_party/linux/.cipd /third_party/linux/clang /third_party/linux/sysroot +/third_party/lss/lss /third_party/gyp/gyp /third_party/mini_chromium/mini_chromium /third_party/zlib/zlib From 7411c8354baf60e4d288185ffc0c8c972554653d Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Mon, 8 Apr 2019 15:48:06 -0700 Subject: [PATCH 173/401] [fuchsia] use source_set for C FIDL library this makes it easier to depend on what we want (the C bindings) rather than having to maintain two lists in sync (sources and deps) Change-Id: Ib3c7715cf8e54658ab44e4de04d04acedf13d09c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1558821 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- third_party/fuchsia/BUILD.gn | 151 ++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 72 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index f712af24..c80926ea 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -58,7 +58,6 @@ if (crashpad_is_in_fuchsia) { }, ] - fidl_gen_sources = [] foreach(fidl_source, fidl_sources) { fidl_stem = "$target_gen_dir/fidl/${fidl_source.library_name}" c_stem = "$fidl_root_gen_dir/${fidl_source.header_stem}/c" @@ -66,11 +65,6 @@ if (crashpad_is_in_fuchsia) { c_client = "$c_stem/client.cc" coding_tables = "$fidl_stem/tables.cc" - fidl_gen_sources += [ - c_client, - coding_tables, - ] - # Compiles the .fidl file and generates the C bindings. action("fidlc_${fidl_source.library_name}") { visibility = [ ":*" ] @@ -102,78 +96,91 @@ if (crashpad_is_in_fuchsia) { coding_tables, ] } + + source_set("${fidl_source.library_name}_c") { + sources = [ + c_client, + c_header, + coding_tables, + ] + + deps = [ + ":fidlc_${fidl_source.library_name}", + ] + + public_configs = [ ":fidl_config" ] + } } static_library("fuchsia") { - sources = - [ - # This is the zx library. - "$sdk_pkg_path/zx/channel.cpp", - "$sdk_pkg_path/zx/event.cpp", - "$sdk_pkg_path/zx/eventpair.cpp", - "$sdk_pkg_path/zx/fifo.cpp", - "$sdk_pkg_path/zx/guest.cpp", - "$sdk_pkg_path/zx/include/lib/zx/bti.h", - "$sdk_pkg_path/zx/include/lib/zx/channel.h", - "$sdk_pkg_path/zx/include/lib/zx/event.h", - "$sdk_pkg_path/zx/include/lib/zx/eventpair.h", - "$sdk_pkg_path/zx/include/lib/zx/fifo.h", - "$sdk_pkg_path/zx/include/lib/zx/guest.h", - "$sdk_pkg_path/zx/include/lib/zx/handle.h", - "$sdk_pkg_path/zx/include/lib/zx/interrupt.h", - "$sdk_pkg_path/zx/include/lib/zx/job.h", - "$sdk_pkg_path/zx/include/lib/zx/object.h", - "$sdk_pkg_path/zx/include/lib/zx/object_traits.h", - "$sdk_pkg_path/zx/include/lib/zx/pmt.h", - "$sdk_pkg_path/zx/include/lib/zx/port.h", - "$sdk_pkg_path/zx/include/lib/zx/process.h", - "$sdk_pkg_path/zx/include/lib/zx/resource.h", - "$sdk_pkg_path/zx/include/lib/zx/socket.h", - "$sdk_pkg_path/zx/include/lib/zx/task.h", - "$sdk_pkg_path/zx/include/lib/zx/thread.h", - "$sdk_pkg_path/zx/include/lib/zx/time.h", - "$sdk_pkg_path/zx/include/lib/zx/timer.h", - "$sdk_pkg_path/zx/include/lib/zx/vmar.h", - "$sdk_pkg_path/zx/include/lib/zx/vmo.h", - "$sdk_pkg_path/zx/interrupt.cpp", - "$sdk_pkg_path/zx/job.cpp", - "$sdk_pkg_path/zx/port.cpp", - "$sdk_pkg_path/zx/process.cpp", - "$sdk_pkg_path/zx/resource.cpp", - "$sdk_pkg_path/zx/socket.cpp", - "$sdk_pkg_path/zx/thread.cpp", - "$sdk_pkg_path/zx/timer.cpp", - "$sdk_pkg_path/zx/vmar.cpp", - "$sdk_pkg_path/zx/vmo.cpp", + sources = [ + # This is the zx library. + "$sdk_pkg_path/zx/channel.cpp", + "$sdk_pkg_path/zx/event.cpp", + "$sdk_pkg_path/zx/eventpair.cpp", + "$sdk_pkg_path/zx/fifo.cpp", + "$sdk_pkg_path/zx/guest.cpp", + "$sdk_pkg_path/zx/include/lib/zx/bti.h", + "$sdk_pkg_path/zx/include/lib/zx/channel.h", + "$sdk_pkg_path/zx/include/lib/zx/event.h", + "$sdk_pkg_path/zx/include/lib/zx/eventpair.h", + "$sdk_pkg_path/zx/include/lib/zx/fifo.h", + "$sdk_pkg_path/zx/include/lib/zx/guest.h", + "$sdk_pkg_path/zx/include/lib/zx/handle.h", + "$sdk_pkg_path/zx/include/lib/zx/interrupt.h", + "$sdk_pkg_path/zx/include/lib/zx/job.h", + "$sdk_pkg_path/zx/include/lib/zx/object.h", + "$sdk_pkg_path/zx/include/lib/zx/object_traits.h", + "$sdk_pkg_path/zx/include/lib/zx/pmt.h", + "$sdk_pkg_path/zx/include/lib/zx/port.h", + "$sdk_pkg_path/zx/include/lib/zx/process.h", + "$sdk_pkg_path/zx/include/lib/zx/resource.h", + "$sdk_pkg_path/zx/include/lib/zx/socket.h", + "$sdk_pkg_path/zx/include/lib/zx/task.h", + "$sdk_pkg_path/zx/include/lib/zx/thread.h", + "$sdk_pkg_path/zx/include/lib/zx/time.h", + "$sdk_pkg_path/zx/include/lib/zx/timer.h", + "$sdk_pkg_path/zx/include/lib/zx/vmar.h", + "$sdk_pkg_path/zx/include/lib/zx/vmo.h", + "$sdk_pkg_path/zx/interrupt.cpp", + "$sdk_pkg_path/zx/job.cpp", + "$sdk_pkg_path/zx/port.cpp", + "$sdk_pkg_path/zx/process.cpp", + "$sdk_pkg_path/zx/resource.cpp", + "$sdk_pkg_path/zx/socket.cpp", + "$sdk_pkg_path/zx/thread.cpp", + "$sdk_pkg_path/zx/timer.cpp", + "$sdk_pkg_path/zx/vmar.cpp", + "$sdk_pkg_path/zx/vmo.cpp", - # This is the fidl_base library. - "$sdk_pkg_path/fidl_base/builder.cpp", - "$sdk_pkg_path/fidl_base/decoding.cpp", - "$sdk_pkg_path/fidl_base/encoding.cpp", - "$sdk_pkg_path/fidl_base/envelope_frames.h", - "$sdk_pkg_path/fidl_base/formatting.cpp", - "$sdk_pkg_path/fidl_base/include/lib/fidl/coding.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/builder.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_buffer.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_builder.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_part.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/string_view.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/vector_view.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/internal.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/internal_callable_traits.h", - "$sdk_pkg_path/fidl_base/linearizing.cpp", - "$sdk_pkg_path/fidl_base/message.cpp", - "$sdk_pkg_path/fidl_base/message_buffer.cpp", - "$sdk_pkg_path/fidl_base/message_builder.cpp", - "$sdk_pkg_path/fidl_base/validating.cpp", - "$sdk_pkg_path/fidl_base/visitor.h", - "$sdk_pkg_path/fidl_base/walker.cpp", - "$sdk_pkg_path/fidl_base/walker.h", - ] + fidl_gen_sources + # This is the fidl_base library. + "$sdk_pkg_path/fidl_base/builder.cpp", + "$sdk_pkg_path/fidl_base/decoding.cpp", + "$sdk_pkg_path/fidl_base/encoding.cpp", + "$sdk_pkg_path/fidl_base/envelope_frames.h", + "$sdk_pkg_path/fidl_base/formatting.cpp", + "$sdk_pkg_path/fidl_base/include/lib/fidl/coding.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/builder.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_buffer.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_builder.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_part.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/string_view.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/vector_view.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/internal.h", + "$sdk_pkg_path/fidl_base/include/lib/fidl/internal_callable_traits.h", + "$sdk_pkg_path/fidl_base/linearizing.cpp", + "$sdk_pkg_path/fidl_base/message.cpp", + "$sdk_pkg_path/fidl_base/message_buffer.cpp", + "$sdk_pkg_path/fidl_base/message_builder.cpp", + "$sdk_pkg_path/fidl_base/validating.cpp", + "$sdk_pkg_path/fidl_base/visitor.h", + "$sdk_pkg_path/fidl_base/walker.cpp", + "$sdk_pkg_path/fidl_base/walker.h", + ] deps = [ - ":fidlc_fuchsia.sysinfo", + ":fuchsia.sysinfo_c", ] public_configs = [ From 0c618f8317c49b3fbdaed629165dd91ff66684df Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 9 Apr 2019 12:56:32 -0700 Subject: [PATCH 174/401] [fuchsia] define zx and fidl_base in their own source_set ideally these source_set would be create programmatically from the corresponding meta.json Change-Id: I4374aef5614c75603132dcdf8d32a687fb9cbadc Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1560077 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- third_party/fuchsia/BUILD.gn | 112 ++++++++++++++--------------------- 1 file changed, 44 insertions(+), 68 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index c80926ea..055a0c84 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -36,13 +36,11 @@ if (crashpad_is_in_fuchsia) { sdk_fidl_sources_path = "$sdk_path/fidl" config("zx_config") { - visibility = [ ":fuchsia" ] include_dirs = [ "$sdk_pkg_path/zx/include" ] } fidl_root_gen_dir = "$root_gen_dir/fidl/include" config("fidl_config") { - visibility = [ ":fuchsia" ] include_dirs = [ fidl_root_gen_dir, "$sdk_pkg_path/fidl/include", @@ -50,6 +48,48 @@ if (crashpad_is_in_fuchsia) { ] } + source_set("zx") { + sources = [ + "$sdk_pkg_path/zx/channel.cpp", + "$sdk_pkg_path/zx/event.cpp", + "$sdk_pkg_path/zx/eventpair.cpp", + "$sdk_pkg_path/zx/fifo.cpp", + "$sdk_pkg_path/zx/guest.cpp", + "$sdk_pkg_path/zx/interrupt.cpp", + "$sdk_pkg_path/zx/job.cpp", + "$sdk_pkg_path/zx/port.cpp", + "$sdk_pkg_path/zx/process.cpp", + "$sdk_pkg_path/zx/resource.cpp", + "$sdk_pkg_path/zx/socket.cpp", + "$sdk_pkg_path/zx/thread.cpp", + "$sdk_pkg_path/zx/timer.cpp", + "$sdk_pkg_path/zx/vmar.cpp", + "$sdk_pkg_path/zx/vmo.cpp", + ] + + public_configs = [ ":zx_config" ] + } + + source_set("fidl_base") { + sources = [ + "$sdk_pkg_path/fidl_base/builder.cpp", + "$sdk_pkg_path/fidl_base/decoding.cpp", + "$sdk_pkg_path/fidl_base/encoding.cpp", + "$sdk_pkg_path/fidl_base/envelope_frames.h", + "$sdk_pkg_path/fidl_base/formatting.cpp", + "$sdk_pkg_path/fidl_base/linearizing.cpp", + "$sdk_pkg_path/fidl_base/message.cpp", + "$sdk_pkg_path/fidl_base/message_buffer.cpp", + "$sdk_pkg_path/fidl_base/message_builder.cpp", + "$sdk_pkg_path/fidl_base/validating.cpp", + "$sdk_pkg_path/fidl_base/visitor.h", + "$sdk_pkg_path/fidl_base/walker.cpp", + "$sdk_pkg_path/fidl_base/walker.h", + ] + + public_configs = [ ":fidl_config" ] + } + fidl_sources = [ { fidl = "$sdk_fidl_sources_path/fuchsia.sysinfo/sysinfo.fidl" @@ -113,74 +153,10 @@ if (crashpad_is_in_fuchsia) { } static_library("fuchsia") { - sources = [ - # This is the zx library. - "$sdk_pkg_path/zx/channel.cpp", - "$sdk_pkg_path/zx/event.cpp", - "$sdk_pkg_path/zx/eventpair.cpp", - "$sdk_pkg_path/zx/fifo.cpp", - "$sdk_pkg_path/zx/guest.cpp", - "$sdk_pkg_path/zx/include/lib/zx/bti.h", - "$sdk_pkg_path/zx/include/lib/zx/channel.h", - "$sdk_pkg_path/zx/include/lib/zx/event.h", - "$sdk_pkg_path/zx/include/lib/zx/eventpair.h", - "$sdk_pkg_path/zx/include/lib/zx/fifo.h", - "$sdk_pkg_path/zx/include/lib/zx/guest.h", - "$sdk_pkg_path/zx/include/lib/zx/handle.h", - "$sdk_pkg_path/zx/include/lib/zx/interrupt.h", - "$sdk_pkg_path/zx/include/lib/zx/job.h", - "$sdk_pkg_path/zx/include/lib/zx/object.h", - "$sdk_pkg_path/zx/include/lib/zx/object_traits.h", - "$sdk_pkg_path/zx/include/lib/zx/pmt.h", - "$sdk_pkg_path/zx/include/lib/zx/port.h", - "$sdk_pkg_path/zx/include/lib/zx/process.h", - "$sdk_pkg_path/zx/include/lib/zx/resource.h", - "$sdk_pkg_path/zx/include/lib/zx/socket.h", - "$sdk_pkg_path/zx/include/lib/zx/task.h", - "$sdk_pkg_path/zx/include/lib/zx/thread.h", - "$sdk_pkg_path/zx/include/lib/zx/time.h", - "$sdk_pkg_path/zx/include/lib/zx/timer.h", - "$sdk_pkg_path/zx/include/lib/zx/vmar.h", - "$sdk_pkg_path/zx/include/lib/zx/vmo.h", - "$sdk_pkg_path/zx/interrupt.cpp", - "$sdk_pkg_path/zx/job.cpp", - "$sdk_pkg_path/zx/port.cpp", - "$sdk_pkg_path/zx/process.cpp", - "$sdk_pkg_path/zx/resource.cpp", - "$sdk_pkg_path/zx/socket.cpp", - "$sdk_pkg_path/zx/thread.cpp", - "$sdk_pkg_path/zx/timer.cpp", - "$sdk_pkg_path/zx/vmar.cpp", - "$sdk_pkg_path/zx/vmo.cpp", - - # This is the fidl_base library. - "$sdk_pkg_path/fidl_base/builder.cpp", - "$sdk_pkg_path/fidl_base/decoding.cpp", - "$sdk_pkg_path/fidl_base/encoding.cpp", - "$sdk_pkg_path/fidl_base/envelope_frames.h", - "$sdk_pkg_path/fidl_base/formatting.cpp", - "$sdk_pkg_path/fidl_base/include/lib/fidl/coding.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/builder.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_buffer.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_builder.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_part.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/string_view.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/vector_view.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/internal.h", - "$sdk_pkg_path/fidl_base/include/lib/fidl/internal_callable_traits.h", - "$sdk_pkg_path/fidl_base/linearizing.cpp", - "$sdk_pkg_path/fidl_base/message.cpp", - "$sdk_pkg_path/fidl_base/message_buffer.cpp", - "$sdk_pkg_path/fidl_base/message_builder.cpp", - "$sdk_pkg_path/fidl_base/validating.cpp", - "$sdk_pkg_path/fidl_base/visitor.h", - "$sdk_pkg_path/fidl_base/walker.cpp", - "$sdk_pkg_path/fidl_base/walker.h", - ] - deps = [ + ":fidl_base", ":fuchsia.sysinfo_c", + ":zx", ] public_configs = [ From 83f6f43d81059865a9ef9db76af74314f385dcca Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 9 Apr 2019 13:30:44 -0700 Subject: [PATCH 175/401] [fuchsia] allow generation of C++ bindings for FIDL dependencies Bug: fuchsia/DX-1270 Change-Id: I99edcfcc96baa00affd129f9249fe6e3c565812b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1560311 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- third_party/fuchsia/BUILD.gn | 104 +++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 4 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 055a0c84..f8d382cc 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -45,6 +45,11 @@ if (crashpad_is_in_fuchsia) { fidl_root_gen_dir, "$sdk_pkg_path/fidl/include", "$sdk_pkg_path/fidl_base/include", + "$sdk_pkg_path/async/include", + "$sdk_pkg_path/fidl_cpp/include", + "$sdk_pkg_path/fidl_cpp_base/include", + "$sdk_pkg_path/fidl_cpp_sync/include", + "$sdk_pkg_path/fit/include", ] } @@ -90,7 +95,26 @@ if (crashpad_is_in_fuchsia) { public_configs = [ ":fidl_config" ] } + source_set("fidl_cpp_base") { + sources = [ + "$sdk_pkg_path/fidl_cpp_base/clone.cc", + "$sdk_pkg_path/fidl_cpp_base/decoder.cc", + "$sdk_pkg_path/fidl_cpp_base/encoder.cc", + "$sdk_pkg_path/fidl_cpp_base/string.cc", + ] + + public_configs = [ + ":fidl_config", + ":zx_config", + ] + } + fidl_sources = [ + { + fidl = "$sdk_fidl_sources_path/fuchsia.mem/buffer.fidl" + header_stem = "fuchsia/mem" + library_name = "fuchsia.mem" + }, { fidl = "$sdk_fidl_sources_path/fuchsia.sysinfo/sysinfo.fidl" header_stem = "fuchsia/sysinfo" @@ -100,12 +124,17 @@ if (crashpad_is_in_fuchsia) { foreach(fidl_source, fidl_sources) { fidl_stem = "$target_gen_dir/fidl/${fidl_source.library_name}" + json_representation = "$fidl_stem/intermediary_representation.json" c_stem = "$fidl_root_gen_dir/${fidl_source.header_stem}/c" c_header = "$c_stem/fidl.h" c_client = "$c_stem/client.cc" + cpp_stem = "$fidl_root_gen_dir/${fidl_source.header_stem}/cpp/fidl" + cpp_header = "$cpp_stem.h" + cpp_source = "$cpp_stem.cc" coding_tables = "$fidl_stem/tables.cc" - # Compiles the .fidl file and generates the C bindings. + # Compiles the .fidl file, outputs the intermediary JSON representation + # and generates the C bindings. action("fidlc_${fidl_source.library_name}") { visibility = [ ":*" ] @@ -119,6 +148,8 @@ if (crashpad_is_in_fuchsia) { rebase_path(c_client, root_build_dir), "--tables", rebase_path(coding_tables, root_build_dir), + "--json", + rebase_path(json_representation, root_build_dir), "--name", fidl_source.library_name, "--files", @@ -134,13 +165,45 @@ if (crashpad_is_in_fuchsia) { c_client, c_header, coding_tables, + json_representation, ] } - source_set("${fidl_source.library_name}_c") { + # Generates the C++ bindings from the intermediary JSON representation. + action("fidlgen_cpp_${fidl_source.library_name}") { + visibility = [ ":*" ] + + script = "runner.py" + + args = [ + rebase_path("$sdk_path/tools/fidlgen", root_build_dir), + "--json", + rebase_path(json_representation, root_build_dir), + "--include-base", + rebase_path(fidl_root_gen_dir, root_build_dir), + "--output-base", + rebase_path(cpp_stem, root_build_dir), + "--generators", + "cpp", + ] + + inputs = [ + "$sdk_path/tools/fidlgen", + json_representation, + ] + + outputs = [ + cpp_header, + cpp_source, + ] + + deps = [ + ":fidlc_${fidl_source.library_name}", + ] + } + + source_set("${fidl_source.library_name}_tables") { sources = [ - c_client, - c_header, coding_tables, ] @@ -150,11 +213,44 @@ if (crashpad_is_in_fuchsia) { public_configs = [ ":fidl_config" ] } + + source_set("${fidl_source.library_name}_c") { + sources = [ + c_client, + c_header, + ] + + deps = [ + ":${fidl_source.library_name}_tables", + ":fidlc_${fidl_source.library_name}", + ] + + public_configs = [ ":fidl_config" ] + } + + source_set("${fidl_source.library_name}_cpp") { + sources = [ + cpp_header, + cpp_source, + ] + + deps = [ + ":${fidl_source.library_name}_tables", + ":fidlgen_cpp_${fidl_source.library_name}", + ] + + public_configs = [ + ":fidl_config", + ":zx_config", + ] + } } static_library("fuchsia") { deps = [ ":fidl_base", + ":fidl_cpp_base", + ":fuchsia.mem_cpp", ":fuchsia.sysinfo_c", ":zx", ] From 77b2b2f1d00881e0e0a8767b478d16b00f31b0ff Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Thu, 4 Apr 2019 14:59:54 -0700 Subject: [PATCH 176/401] [fuchsia] change attachments from filepaths to VMOs * we start with VMOs in Fuchsia so this avoids a temporary file before writing the files in the database * in order to do a soft transition, we add the new type and leave the old one until the caller in Fuchsia has been updated. Bug: fuchsia:DX-1270 Change-Id: I3c77c775a186801dbcc7379e84ad5795f41780e7 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1554011 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- .../fuchsia/crash_report_exception_handler.cc | 39 +++++++++++++++++++ .../fuchsia/crash_report_exception_handler.h | 36 +++++++++++++++++ handler/handler_main.cc | 2 +- third_party/fuchsia/BUILD.gn | 2 + 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index 0d1ee304..ec9a9731 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -15,6 +15,8 @@ #include "handler/fuchsia/crash_report_exception_handler.h" #include <lib/zx/thread.h> +#include <zircon/errors.h> +#include <zircon/status.h> #include <zircon/syscalls/exception.h> #include "base/fuchsia/fuchsia_logging.h" @@ -64,6 +66,20 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( upload_thread_(upload_thread), process_annotations_(process_annotations), process_attachments_(process_attachments), + process_attachments_vmo_(nullptr), + user_stream_data_sources_(user_stream_data_sources) {} + +CrashReportExceptionHandler::CrashReportExceptionHandler( + CrashReportDatabase* database, + CrashReportUploadThread* upload_thread, + const std::map<std::string, std::string>* process_annotations, + const std::map<std::string, fuchsia::mem::Buffer>* process_attachments, + const UserStreamDataSources* user_stream_data_sources) + : database_(database), + upload_thread_(upload_thread), + process_annotations_(process_annotations), + process_attachments_(nullptr), + process_attachments_vmo_(process_attachments), user_stream_data_sources_(user_stream_data_sources) {} CrashReportExceptionHandler::~CrashReportExceptionHandler() {} @@ -163,6 +179,7 @@ bool CrashReportExceptionHandler::HandleExceptionHandles( return false; } + // TODO(DX-1270): remove once callers have switched to passing VMOs. 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 @@ -179,6 +196,28 @@ bool CrashReportExceptionHandler::HandleExceptionHandles( writer->Write(contents.data(), contents.size()); } } + } else if (process_attachments_vmo_) { + // Note that attachments are read at this point each time rather than once + // so that if the contents of the VMO 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_vmo_) { + // TODO(frousseau): make FileWriter VMO-aware. + FileWriter* writer = new_report->AddAttachment(it.first); + if (!writer) { + continue; + } + auto data = std::make_unique<uint8_t[]>(it.second.size); + const zx_status_t read_status = + it.second.vmo.read(data.get(), 0u, it.second.size); + if (read_status != ZX_OK) { + ZX_LOG(ERROR, read_status) + << "could not read VMO for attachment " << it.first; + // Not being able to read the VMO isn't considered fatal, and + // should not prevent the report from being processed. + continue; + } + writer->Write(data.get(), it.second.size); + } } UUID uuid; diff --git a/handler/fuchsia/crash_report_exception_handler.h b/handler/fuchsia/crash_report_exception_handler.h index 88b4cca2..ee68d945 100644 --- a/handler/fuchsia/crash_report_exception_handler.h +++ b/handler/fuchsia/crash_report_exception_handler.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_HANDLER_FUCHSIA_CRASH_REPORT_EXCEPTION_HANDLER_H_ #define CRASHPAD_HANDLER_FUCHSIA_CRASH_REPORT_EXCEPTION_HANDLER_H_ +#include <fuchsia/mem/cpp/fidl.h> #include <lib/zx/port.h> #include <lib/zx/process.h> #include <lib/zx/thread.h> @@ -60,6 +61,8 @@ class CrashReportExceptionHandler { //! crash reports. For each crash report that is written, the data sources //! are called in turn. These data sources may contribute additional //! minidump streams. `nullptr` if not required. + // + // TODO(DX-1270): remove once callers have switched to passing VMOs. CrashReportExceptionHandler( CrashReportDatabase* database, CrashReportUploadThread* upload_thread, @@ -67,6 +70,36 @@ class CrashReportExceptionHandler { const std::map<std::string, base::FilePath>* process_attachments, const UserStreamDataSources* user_stream_data_sources); + //! \brief Creates a new object that will store crash reports in \a database. + //! + //! \param[in] database The database to store crash reports in. Weak. + //! \param[in] upload_thread The upload thread to notify when a new crash + //! report is written into \a database. + //! \param[in] process_annotations A map of annotations to insert as + //! process-level annotations into each crash report that is written. Do + //! not confuse this with module-level annotations, which are under the + //! control of the crashing process, and are used to implement Chrome's + //! "crash keys." Process-level annotations are those that are beyond the + //! control of the crashing process, which must reliably be set even if + //! the process crashes before it’s able to establish its own annotations. + //! 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 keys to VMOs to be included in the + //! report. Each time a report is written, the VMOs will be read in their + //! entirety and included in the report using the 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 + //! minidump streams. `nullptr` if not required. + CrashReportExceptionHandler( + CrashReportDatabase* database, + CrashReportUploadThread* upload_thread, + const std::map<std::string, std::string>* process_annotations, + const std::map<std::string, fuchsia::mem::Buffer>* process_attachments, + const UserStreamDataSources* user_stream_data_sources); + ~CrashReportExceptionHandler(); //! \brief Called when the exception handler server has caught an exception @@ -112,7 +145,10 @@ class CrashReportExceptionHandler { CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak const std::map<std::string, std::string>* process_annotations_; // weak + // TODO(DX-1270): remove once callers have switched to passing VMOs. const std::map<std::string, base::FilePath>* process_attachments_; // weak + const std::map<std::string, fuchsia::mem::Buffer>* + process_attachments_vmo_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler); diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 31686b3e..b643b111 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -874,7 +874,7 @@ int HandlerMain(int argc, &options.annotations, #if defined(OS_FUCHSIA) // TODO(scottmg): Process level file attachments, and for all platforms. - nullptr, + static_cast<std::map<std::string, base::FilePath>*>(nullptr), #endif user_stream_sources); diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index f8d382cc..f10ccd0d 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -17,6 +17,7 @@ import("../../build/crashpad_buildconfig.gni") if (crashpad_is_in_fuchsia) { group("fuchsia") { public_deps = [ + "//zircon/public/fidl/fuchsia-mem", "//zircon/public/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c", "//zircon/public/lib/fdio", "//zircon/public/lib/zx", @@ -26,6 +27,7 @@ if (crashpad_is_in_fuchsia) { group("fuchsia") { public_deps = [ "//third_party/fuchsia-sdk/sdk:fdio", + "//third_party/fuchsia-sdk/sdk:mem", "//third_party/fuchsia-sdk/sdk:sysinfo", "//third_party/fuchsia-sdk/sdk:zx", ] From 5081a90207ec5e39aefeeab4ccc3e4690ee5c1e5 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Wed, 10 Apr 2019 13:14:43 -0700 Subject: [PATCH 177/401] [fuchsia] delete old way of passing attachments * Fuchsia has switched to passing VMOs directly Bug: fuchsia:DX-1270 Change-Id: I8114a87d895602e80757b87cbeb884b62cfae57f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1562180 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- .../fuchsia/crash_report_exception_handler.cc | 35 ++---------------- .../fuchsia/crash_report_exception_handler.h | 36 +------------------ handler/handler_main.cc | 2 +- 3 files changed, 4 insertions(+), 69 deletions(-) diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index ec9a9731..b181cb60 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -56,19 +56,6 @@ class ScopedThreadResumeAfterException { } // namespace -CrashReportExceptionHandler::CrashReportExceptionHandler( - CrashReportDatabase* database, - CrashReportUploadThread* upload_thread, - const std::map<std::string, std::string>* process_annotations, - const std::map<std::string, base::FilePath>* process_attachments, - const UserStreamDataSources* user_stream_data_sources) - : database_(database), - upload_thread_(upload_thread), - process_annotations_(process_annotations), - process_attachments_(process_attachments), - process_attachments_vmo_(nullptr), - user_stream_data_sources_(user_stream_data_sources) {} - CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportDatabase* database, CrashReportUploadThread* upload_thread, @@ -78,8 +65,7 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( : database_(database), upload_thread_(upload_thread), process_annotations_(process_annotations), - process_attachments_(nullptr), - process_attachments_vmo_(process_attachments), + process_attachments_(process_attachments), user_stream_data_sources_(user_stream_data_sources) {} CrashReportExceptionHandler::~CrashReportExceptionHandler() {} @@ -179,28 +165,11 @@ bool CrashReportExceptionHandler::HandleExceptionHandles( return false; } - // TODO(DX-1270): remove once callers have switched to passing VMOs. 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()); - } - } - } else if (process_attachments_vmo_) { // Note that attachments are read at this point each time rather than once // so that if the contents of the VMO 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_vmo_) { + for (const auto& it : *process_attachments_) { // TODO(frousseau): make FileWriter VMO-aware. FileWriter* writer = new_report->AddAttachment(it.first); if (!writer) { diff --git a/handler/fuchsia/crash_report_exception_handler.h b/handler/fuchsia/crash_report_exception_handler.h index ee68d945..c636fcae 100644 --- a/handler/fuchsia/crash_report_exception_handler.h +++ b/handler/fuchsia/crash_report_exception_handler.h @@ -38,38 +38,6 @@ namespace crashpad { //! to a CrashReportDatabase. class CrashReportExceptionHandler { public: - //! \brief Creates a new object that will store crash reports in \a database. - //! - //! \param[in] database The database to store crash reports in. Weak. - //! \param[in] upload_thread The upload thread to notify when a new crash - //! report is written into \a database. - //! \param[in] process_annotations A map of annotations to insert as - //! process-level annotations into each crash report that is written. Do - //! not confuse this with module-level annotations, which are under the - //! control of the crashing process, and are used to implement Chrome's - //! "crash keys." Process-level annotations are those that are beyond the - //! control of the crashing process, which must reliably be set even if - //! the process crashes before it’s able to establish its own annotations. - //! 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 - //! minidump streams. `nullptr` if not required. - // - // TODO(DX-1270): remove once callers have switched to passing VMOs. - CrashReportExceptionHandler( - CrashReportDatabase* database, - CrashReportUploadThread* upload_thread, - const std::map<std::string, std::string>* process_annotations, - const std::map<std::string, base::FilePath>* process_attachments, - const UserStreamDataSources* user_stream_data_sources); - //! \brief Creates a new object that will store crash reports in \a database. //! //! \param[in] database The database to store crash reports in. Weak. @@ -145,10 +113,8 @@ class CrashReportExceptionHandler { CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak const std::map<std::string, std::string>* process_annotations_; // weak - // TODO(DX-1270): remove once callers have switched to passing VMOs. - const std::map<std::string, base::FilePath>* process_attachments_; // weak const std::map<std::string, fuchsia::mem::Buffer>* - process_attachments_vmo_; // weak + process_attachments_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler); diff --git a/handler/handler_main.cc b/handler/handler_main.cc index b643b111..31686b3e 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -874,7 +874,7 @@ int HandlerMain(int argc, &options.annotations, #if defined(OS_FUCHSIA) // TODO(scottmg): Process level file attachments, and for all platforms. - static_cast<std::map<std::string, base::FilePath>*>(nullptr), + nullptr, #endif user_stream_sources); From ad49fcfad60ddba27a8a402d1c80cac1c2470353 Mon Sep 17 00:00:00 2001 From: Egor Pasko <pasko@chromium.org> Date: Thu, 11 Apr 2019 16:34:02 +0200 Subject: [PATCH 178/401] directory_reader_posix: more verbosity in PLOG Bug: chromium:949321 Change-Id: I0c73d730ede912a7be0b22ea3ab384a8fda2e528 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1564512 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Egor Pasko <pasko@chromium.org> --- util/file/directory_reader_posix.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/file/directory_reader_posix.cc b/util/file/directory_reader_posix.cc index b33e19bb..475b0b18 100644 --- a/util/file/directory_reader_posix.cc +++ b/util/file/directory_reader_posix.cc @@ -39,7 +39,7 @@ DirectoryReader::~DirectoryReader() {} bool DirectoryReader::Open(const base::FilePath& path) { dir_.reset(HANDLE_EINTR_IF_EQ(opendir(path.value().c_str()), nullptr)); if (!dir_.is_valid()) { - PLOG(ERROR) << "opendir"; + PLOG(ERROR) << "opendir " << path.value(); return false; } return true; @@ -52,7 +52,7 @@ DirectoryReader::Result DirectoryReader::NextFile(base::FilePath* filename) { dirent* entry = HANDLE_EINTR_IF_EQ(readdir(dir_.get()), nullptr); if (!entry) { if (errno) { - PLOG(ERROR) << "readdir"; + PLOG(ERROR) << "readdir " << filename->value(); return Result::kError; } else { return Result::kNoMoreFiles; From e50676dcf243d6ad3f55446afaf2f5317b43d43a Mon Sep 17 00:00:00 2001 From: Eric Astor <epastor@google.com> Date: Fri, 12 Apr 2019 13:42:44 -0400 Subject: [PATCH 179/401] Switch all string-number conversion to use fundamental types, and add long to the list. Change-Id: I9244df09415f9d46262e2b8d04b64d7c4f786436 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1565287 Commit-Queue: Eric Astor <epastor@google.com> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/stdlib/string_number_conversion.cc | 46 ++- util/stdlib/string_number_conversion.h | 6 +- util/stdlib/string_number_conversion_test.cc | 325 ++++++++++++------- 3 files changed, 248 insertions(+), 129 deletions(-) diff --git a/util/stdlib/string_number_conversion.cc b/util/stdlib/string_number_conversion.cc index 859a8333..64211844 100644 --- a/util/stdlib/string_number_conversion.cc +++ b/util/stdlib/string_number_conversion.cc @@ -97,15 +97,34 @@ struct StringToUnsignedIntTraits } }; -struct StringToInt64Traits - : public StringToSignedIntegerTraits<int64_t, int64_t> { +struct StringToLongTraits + : public StringToSignedIntegerTraits<long, long long> { static LongType Convert(const char* str, char** end, int base) { return strtoll(str, end, base); } }; -struct StringToUnsignedInt64Traits - : public StringToUnsignedIntegerTraits<uint64_t, uint64_t> { +struct StringToUnsignedLongTraits + : public StringToUnsignedIntegerTraits<unsigned long, unsigned long long> { + static LongType Convert(const char* str, char** end, int base) { + if (str[0] == '-') { + *end = const_cast<char*>(str); + return 0; + } + return strtoull(str, end, base); + } +}; + +struct StringToLongLongTraits + : public StringToSignedIntegerTraits<long long, long long> { + static LongType Convert(const char* str, char** end, int base) { + return strtoll(str, end, base); + } +}; + +struct StringToUnsignedLongLongTraits + : public StringToUnsignedIntegerTraits<unsigned long long, + unsigned long long> { static LongType Convert(const char* str, char** end, int base) { if (str[0] == '-') { *end = const_cast<char*>(str); @@ -136,7 +155,7 @@ bool StringToIntegerInternal(const std::string& string, end != string.data() + string.length()) { return false; } - *number = result; + *number = static_cast<IntType>(result); return true; } @@ -152,12 +171,21 @@ bool StringToNumber(const std::string& string, unsigned int* number) { return StringToIntegerInternal<StringToUnsignedIntTraits>(string, number); } -bool StringToNumber(const std::string& string, int64_t* number) { - return StringToIntegerInternal<StringToInt64Traits>(string, number); +bool StringToNumber(const std::string& string, long* number) { + return StringToIntegerInternal<StringToLongTraits>(string, number); } -bool StringToNumber(const std::string& string, uint64_t* number) { - return StringToIntegerInternal<StringToUnsignedInt64Traits>(string, number); +bool StringToNumber(const std::string& string, unsigned long* number) { + return StringToIntegerInternal<StringToUnsignedLongTraits>(string, number); +} + +bool StringToNumber(const std::string& string, long long* number) { + return StringToIntegerInternal<StringToLongLongTraits>(string, number); +} + +bool StringToNumber(const std::string& string, unsigned long long* number) { + return StringToIntegerInternal<StringToUnsignedLongLongTraits>(string, + number); } } // namespace crashpad diff --git a/util/stdlib/string_number_conversion.h b/util/stdlib/string_number_conversion.h index b5f1d44a..69e7fdd6 100644 --- a/util/stdlib/string_number_conversion.h +++ b/util/stdlib/string_number_conversion.h @@ -56,8 +56,10 @@ namespace crashpad { //! where such prefix recognition is desirable. bool StringToNumber(const std::string& string, int* number); bool StringToNumber(const std::string& string, unsigned int* number); -bool StringToNumber(const std::string& string, int64_t* number); -bool StringToNumber(const std::string& string, uint64_t* number); +bool StringToNumber(const std::string& string, long* number); +bool StringToNumber(const std::string& string, unsigned long* number); +bool StringToNumber(const std::string& string, long long* number); +bool StringToNumber(const std::string& string, unsigned long long* number); //! \} } // namespace crashpad diff --git a/util/stdlib/string_number_conversion_test.cc b/util/stdlib/string_number_conversion_test.cc index 689b4ad5..760dc4a8 100644 --- a/util/stdlib/string_number_conversion_test.cc +++ b/util/stdlib/string_number_conversion_test.cc @@ -16,30 +16,39 @@ #include <sys/types.h> +#include <array> #include <limits> +#include <type_traits> #include "base/stl_util.h" #include "gtest/gtest.h" -namespace crashpad { -namespace test { -namespace { +#define STRINGIFY(a) STR(a) +#define STR(a) #a -TEST(StringNumberConversion, StringToInt) { - static constexpr struct { - const char* string; - bool valid; - int value; - } kTestData[] = { +template <typename TValueType> +struct TestSpecification { + const char* string; + bool valid; + TValueType value; +}; + +// Signed 32-bit test data +template <typename TIntType, + typename std::enable_if<std::is_integral<TIntType>::value && + std::is_signed<TIntType>::value && + (sizeof(TIntType) == 4)>::type* = nullptr> +static constexpr std::array<TestSpecification<TIntType>, 61> kTestDataFunc() { + return {{ {"", false, 0}, {"0", true, 0}, {"1", true, 1}, - {"2147483647", true, std::numeric_limits<int>::max()}, + {"2147483647", true, std::numeric_limits<TIntType>::max()}, {"2147483648", false, 0}, {"4294967295", false, 0}, {"4294967296", false, 0}, {"-1", true, -1}, - {"-2147483648", true, std::numeric_limits<int>::min()}, + {"-2147483648", true, std::numeric_limits<TIntType>::min()}, {"-2147483649", false, 0}, {"00", true, 0}, {"01", true, 1}, @@ -50,12 +59,12 @@ TEST(StringNumberConversion, StringToInt) { {"+0x20", true, 32}, {"0xf", true, 15}, {"0xg", false, 0}, - {"0x7fffffff", true, std::numeric_limits<int>::max()}, - {"0x7FfFfFfF", true, std::numeric_limits<int>::max()}, + {"0x7fffffff", true, std::numeric_limits<TIntType>::max()}, + {"0x7FfFfFfF", true, std::numeric_limits<TIntType>::max()}, {"0x80000000", false, 0}, {"0xFFFFFFFF", false, 0}, {"-0x7fffffff", true, -2147483647}, - {"-0x80000000", true, std::numeric_limits<int>::min()}, + {"-0x80000000", true, std::numeric_limits<TIntType>::min()}, {"-0x80000001", false, 0}, {"-0xffffffff", false, 0}, {"0x100000000", false, 0}, @@ -92,45 +101,22 @@ TEST(StringNumberConversion, StringToInt) { {"9223372036854775809", false, 0}, {"18446744073709551615", false, 0}, {"18446744073709551616", false, 0}, - }; - - for (size_t index = 0; index < base::size(kTestData); ++index) { - int value; - bool valid = StringToNumber(kTestData[index].string, &value); - if (kTestData[index].valid) { - EXPECT_TRUE(valid) << "index " << index << ", string " - << kTestData[index].string; - if (valid) { - EXPECT_EQ(value, kTestData[index].value) - << "index " << index << ", string " << kTestData[index].string; - } - } else { - EXPECT_FALSE(valid) << "index " << index << ", string " - << kTestData[index].string << ", value " << value; - } - } - - // Ensure that embedded NUL characters are treated as bad input. The string - // is split to avoid MSVC warning: - // "decimal digit terminates octal escape sequence". - static constexpr char input[] = "6\000" "6"; - std::string input_string(input, base::size(input) - 1); - int output; - EXPECT_FALSE(StringToNumber(input_string, &output)); + }}; } -TEST(StringNumberConversion, StringToUnsignedInt) { - static constexpr struct { - const char* string; - bool valid; - unsigned int value; - } kTestData[] = { +// Unsigned 32-bit test data +template <typename TIntType, + typename std::enable_if<std::is_integral<TIntType>::value && + !std::is_signed<TIntType>::value && + (sizeof(TIntType) == 4)>::type* = nullptr> +static constexpr std::array<TestSpecification<TIntType>, 61> kTestDataFunc() { + return {{ {"", false, 0}, {"0", true, 0}, {"1", true, 1}, {"2147483647", true, 2147483647}, {"2147483648", true, 2147483648}, - {"4294967295", true, std::numeric_limits<unsigned int>::max()}, + {"4294967295", true, std::numeric_limits<TIntType>::max()}, {"4294967296", false, 0}, {"-1", false, 0}, {"-2147483648", false, 0}, @@ -186,9 +172,121 @@ TEST(StringNumberConversion, StringToUnsignedInt) { {"9223372036854775809", false, 0}, {"18446744073709551615", false, 0}, {"18446744073709551616", false, 0}, - }; + }}; +} - for (size_t index = 0; index < base::size(kTestData); ++index) { +// Signed 64-bit test data +template <typename TIntType, + typename std::enable_if<std::is_integral<TIntType>::value && + std::is_signed<TIntType>::value && + (sizeof(TIntType) == 8)>::type* = nullptr> +static constexpr std::array<TestSpecification<TIntType>, 24> kTestDataFunc() { + return {{ + {"", false, 0}, + {"0", true, 0}, + {"1", true, 1}, + {"2147483647", true, 2147483647}, + {"2147483648", true, 2147483648}, + {"4294967295", true, 4294967295}, + {"4294967296", true, 4294967296}, + {"9223372036854775807", true, std::numeric_limits<TIntType>::max()}, + {"9223372036854775808", false, 0}, + {"18446744073709551615", false, 0}, + {"18446744073709551616", false, 0}, + {"-1", true, -1}, + {"-2147483648", true, INT64_C(-2147483648)}, + {"-2147483649", true, INT64_C(-2147483649)}, + {"-9223372036854775808", true, std::numeric_limits<TIntType>::min()}, + {"-9223372036854775809", false, 0}, + {"0x7fffffffffffffff", true, std::numeric_limits<TIntType>::max()}, + {"0x8000000000000000", false, 0}, + {"0xffffffffffffffff", false, 0}, + {"0x10000000000000000", false, 0}, + {"-0x7fffffffffffffff", true, -9223372036854775807}, + {"-0x8000000000000000", true, std::numeric_limits<TIntType>::min()}, + {"-0x8000000000000001", false, 0}, + {"0x7Fffffffffffffff", true, std::numeric_limits<TIntType>::max()}, + }}; +} + +// Unsigned 64-bit test data +template <typename TIntType, + typename std::enable_if<std::is_integral<TIntType>::value && + !std::is_signed<TIntType>::value && + (sizeof(TIntType) == 8)>::type* = nullptr> +static constexpr std::array<TestSpecification<TIntType>, 25> kTestDataFunc() { + return {{ + {"", false, 0}, + {"0", true, 0}, + {"1", true, 1}, + {"2147483647", true, 2147483647}, + {"2147483648", true, 2147483648}, + {"4294967295", true, 4294967295}, + {"4294967296", true, 4294967296}, + {"9223372036854775807", true, 9223372036854775807}, + {"9223372036854775808", true, 9223372036854775808u}, + {"18446744073709551615", true, std::numeric_limits<TIntType>::max()}, + {"18446744073709551616", false, 0}, + {"-1", false, 0}, + {"-2147483648", false, 0}, + {"-2147483649", false, 0}, + {"-2147483648", false, 0}, + {"-9223372036854775808", false, 0}, + {"-9223372036854775809", false, 0}, + {"0x7fffffffffffffff", true, 9223372036854775807}, + {"0x8000000000000000", true, 9223372036854775808u}, + {"0xffffffffffffffff", true, std::numeric_limits<TIntType>::max()}, + {"0x10000000000000000", false, 0}, + {"-0x7fffffffffffffff", false, 0}, + {"-0x8000000000000000", false, 0}, + {"-0x8000000000000001", false, 0}, + {"0xFfffffffffffffff", true, std::numeric_limits<TIntType>::max()}, + }}; +} + +// This string is split to avoid MSVC warning: +// "decimal digit terminates octal escape sequence". +static constexpr char kEmbeddedNullInputRaw[] = "6\000" "6"; + +namespace crashpad { +namespace test { +namespace { + +TEST(StringNumberConversion, StringToInt) { + static_assert(sizeof(int) == 4, "Test only configured for 32-bit int."); + static constexpr auto kTestData = kTestDataFunc<int>(); + + for (size_t index = 0; index < kTestData.size(); ++index) { + int value; + bool valid = StringToNumber(kTestData[index].string, &value); + if (kTestData[index].valid) { + EXPECT_TRUE(valid) << "index " << index << ", string " + << kTestData[index].string; + if (valid) { + EXPECT_EQ(value, kTestData[index].value) + << "index " << index << ", string " << kTestData[index].string; + } + } else { + EXPECT_FALSE(valid) << "index " << index << ", string " + << kTestData[index].string << ", value " << value; + } + } + + // Ensure that embedded NUL characters are treated as bad input. The string + // is split to avoid MSVC warning: + // "decimal digit terminates octal escape sequence". + int output; + std::string kEmbeddedNullInput(kEmbeddedNullInputRaw, + base::size(kEmbeddedNullInputRaw) - 1); + EXPECT_FALSE(StringToNumber(kEmbeddedNullInput, &output)); +} + +TEST(StringNumberConversion, StringToUnsignedInt) { + static_assert(sizeof(unsigned int) == 4, + "Test only configured for 32-bit unsigned int."); + static constexpr auto kTestData = kTestDataFunc<unsigned int>(); + + for (size_t index = 0; index < kTestData.size(); ++index) { unsigned int value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { @@ -207,46 +305,20 @@ TEST(StringNumberConversion, StringToUnsignedInt) { // Ensure that embedded NUL characters are treated as bad input. The string // is split to avoid MSVC warning: // "decimal digit terminates octal escape sequence". - static constexpr char input[] = "6\000" "6"; - std::string input_string(input, base::size(input) - 1); unsigned int output; - EXPECT_FALSE(StringToNumber(input_string, &output)); + std::string kEmbeddedNullInput(kEmbeddedNullInputRaw, + base::size(kEmbeddedNullInputRaw) - 1); + EXPECT_FALSE(StringToNumber(kEmbeddedNullInput, &output)); } -TEST(StringNumberConversion, StringToInt64) { - static constexpr struct { - const char* string; - bool valid; - int64_t value; - } kTestData[] = { - {"", false, 0}, - {"0", true, 0}, - {"1", true, 1}, - {"2147483647", true, 2147483647}, - {"2147483648", true, 2147483648}, - {"4294967295", true, 4294967295}, - {"4294967296", true, 4294967296}, - {"9223372036854775807", true, std::numeric_limits<int64_t>::max()}, - {"9223372036854775808", false, 0}, - {"18446744073709551615", false, 0}, - {"18446744073709551616", false, 0}, - {"-1", true, -1}, - {"-2147483648", true, INT64_C(-2147483648)}, - {"-2147483649", true, INT64_C(-2147483649)}, - {"-9223372036854775808", true, std::numeric_limits<int64_t>::min()}, - {"-9223372036854775809", false, 0}, - {"0x7fffffffffffffff", true, std::numeric_limits<int64_t>::max()}, - {"0x8000000000000000", false, 0}, - {"0xffffffffffffffff", false, 0}, - {"0x10000000000000000", false, 0}, - {"-0x7fffffffffffffff", true, -9223372036854775807}, - {"-0x8000000000000000", true, std::numeric_limits<int64_t>::min()}, - {"-0x8000000000000001", false, 0}, - {"0x7Fffffffffffffff", true, std::numeric_limits<int64_t>::max()}, - }; +TEST(StringNumberConversion, StringToLong) { + static_assert( + sizeof(long) == 4 || sizeof(long) == 8, + "Test not configured for " STRINGIFY(__SIZEOF_LONG__) "-byte long"); + static constexpr auto kTestData = kTestDataFunc<long>(); - for (size_t index = 0; index < base::size(kTestData); ++index) { - int64_t value; + for (size_t index = 0; index < kTestData.size(); ++index) { + long value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { EXPECT_TRUE(valid) << "index " << index << ", string " @@ -262,41 +334,58 @@ TEST(StringNumberConversion, StringToInt64) { } } -TEST(StringNumberConversion, StringToUnsignedInt64) { - static constexpr struct { - const char* string; - bool valid; - uint64_t value; - } kTestData[] = { - {"", false, 0}, - {"0", true, 0}, - {"1", true, 1}, - {"2147483647", true, 2147483647}, - {"2147483648", true, 2147483648}, - {"4294967295", true, 4294967295}, - {"4294967296", true, 4294967296}, - {"9223372036854775807", true, 9223372036854775807}, - {"9223372036854775808", true, 9223372036854775808u}, - {"18446744073709551615", true, std::numeric_limits<uint64_t>::max()}, - {"18446744073709551616", false, 0}, - {"-1", false, 0}, - {"-2147483648", false, 0}, - {"-2147483649", false, 0}, - {"-2147483648", false, 0}, - {"-9223372036854775808", false, 0}, - {"-9223372036854775809", false, 0}, - {"0x7fffffffffffffff", true, 9223372036854775807}, - {"0x8000000000000000", true, 9223372036854775808u}, - {"0xffffffffffffffff", true, std::numeric_limits<uint64_t>::max()}, - {"0x10000000000000000", false, 0}, - {"-0x7fffffffffffffff", false, 0}, - {"-0x8000000000000000", false, 0}, - {"-0x8000000000000001", false, 0}, - {"0xFfffffffffffffff", true, std::numeric_limits<uint64_t>::max()}, - }; +TEST(StringNumberConversion, StringToUnsignedLong) { + static_assert( + sizeof(long) == 4 || sizeof(long) == 8, + "Test not configured for " STRINGIFY(__SIZEOF_LONG__) "-byte long"); + static constexpr auto kTestData = kTestDataFunc<unsigned long>(); - for (size_t index = 0; index < base::size(kTestData); ++index) { - uint64_t value; + for (size_t index = 0; index < kTestData.size(); ++index) { + unsigned long value; + bool valid = StringToNumber(kTestData[index].string, &value); + if (kTestData[index].valid) { + EXPECT_TRUE(valid) << "index " << index << ", string " + << kTestData[index].string; + if (valid) { + EXPECT_EQ(value, kTestData[index].value) + << "index " << index << ", string " << kTestData[index].string; + } + } else { + EXPECT_FALSE(valid) << "index " << index << ", string " + << kTestData[index].string << ", value " << value; + } + } +} + +TEST(StringNumberConversion, StringToLongLong) { + static_assert(sizeof(long long) == 8, + "Test only configured for 64-bit long long."); + static constexpr auto kTestData = kTestDataFunc<long long>(); + + for (size_t index = 0; index < kTestData.size(); ++index) { + long long value; + bool valid = StringToNumber(kTestData[index].string, &value); + if (kTestData[index].valid) { + EXPECT_TRUE(valid) << "index " << index << ", string " + << kTestData[index].string; + if (valid) { + EXPECT_EQ(value, kTestData[index].value) + << "index " << index << ", string " << kTestData[index].string; + } + } else { + EXPECT_FALSE(valid) << "index " << index << ", string " + << kTestData[index].string << ", value " << value; + } + } +} + +TEST(StringNumberConversion, StringToUnsignedLongLong) { + static_assert(sizeof(unsigned long long) == 8, + "Test only configured for 64-bit unsigned long long."); + static constexpr auto kTestData = kTestDataFunc<unsigned long long>(); + + for (size_t index = 0; index < kTestData.size(); ++index) { + unsigned long long value; bool valid = StringToNumber(kTestData[index].string, &value); if (kTestData[index].valid) { EXPECT_TRUE(valid) << "index " << index << ", string " From 1c78fe23bd90faae5a5148b6c34aa835ebfb9224 Mon Sep 17 00:00:00 2001 From: Peter Wen <wnwen@chromium.org> Date: Mon, 15 Apr 2019 14:24:03 -0400 Subject: [PATCH 180/401] Update doc/developing.md with linux details This information is very helpful to someone new to Crashpad to be able to get up and running quickly (i.e. what I would have needed). Bug: crashpad:291 Change-Id: Ibc84a009dbd7c93dd098e658cbe895957c6dca16 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1567847 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Peter Wen <wnwen@chromium.org> --- doc/developing.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/developing.md b/doc/developing.md index 4aaac6c1..af557a53 100644 --- a/doc/developing.md +++ b/doc/developing.md @@ -106,6 +106,21 @@ GN and Ninja are part of the [depot_tools](https://www.chromium.org/developers/how-tos/depottools). There’s no need to install them separately. +#### Optional Linux Configs + +To pull and use Crashpad's version of clang and sysroot, make the following +changes. + +Add the following to `~/crashpad/.gclient`. +``` +"custom_vars": { "pull_linux_clang": True }, +``` +Add these args to `out/Default/args.gn`. +``` +clang_path = "//third_party/linux/clang/linux-amd64" +target_sysroot = "//third_party/linux/sysroot" +``` + ### Android Crashpad’s Android port is in its early stages. This build relies on From c31a86a340f309e01d4949fa8a38bcd5ac1af991 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 16 Apr 2019 11:01:27 -0700 Subject: [PATCH 181/401] linux: Identify requesting threads When a crashing process is in a different PID namespace than the handler, the crasher doesn't have a way of knowing its own thread ID in the handler's namespace and the kernel lacks mechanisms to perform this translation before Linux 4.1 (where the information is present in /proc/<pid>/status:NSPid). This patch gives the handler a way of identifying the requesting thread by sending a stack address along with the crash dump request, which the handler can search for in each of the process' threads. This information is useful both for attaching exception information to the right thread and to allow the handler to send signals to the correct thread when using a shared socket connection. Bug: crashpad:284, crashpad:286 Change-Id: I4fa366c8fb17f932b056265cf71a4af160ba342f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1558828 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- .../linux/crash_report_exception_handler.cc | 25 +++++++++++++++---- .../linux/crash_report_exception_handler.h | 4 +++ handler/linux/exception_handler_server.cc | 10 +++++--- handler/linux/exception_handler_server.h | 9 +++++++ .../linux/exception_handler_server_test.cc | 22 +++++++++++++++- snapshot/linux/process_snapshot_linux.cc | 14 +++++++++++ snapshot/linux/process_snapshot_linux.h | 7 ++++++ util/linux/exception_handler_client.cc | 10 +++++--- util/linux/exception_handler_client.h | 3 ++- util/linux/exception_handler_protocol.h | 3 +++ 10 files changed, 94 insertions(+), 13 deletions(-) diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 910b2884..5401bafa 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -43,9 +43,12 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportExceptionHandler::~CrashReportExceptionHandler() = default; -bool CrashReportExceptionHandler::HandleException(pid_t client_process_id, - const ClientInformation& info, - UUID* local_report_id) { +bool CrashReportExceptionHandler::HandleException( + pid_t client_process_id, + const ClientInformation& info, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id, + UUID* local_report_id) { Metrics::ExceptionEncountered(); DirectPtraceConnection connection; @@ -55,7 +58,11 @@ bool CrashReportExceptionHandler::HandleException(pid_t client_process_id, return false; } - return HandleExceptionWithConnection(&connection, info, local_report_id); + return HandleExceptionWithConnection(&connection, + info, + requesting_thread_stack_address, + requesting_thread_id, + local_report_id); } bool CrashReportExceptionHandler::HandleExceptionWithBroker( @@ -72,12 +79,15 @@ bool CrashReportExceptionHandler::HandleExceptionWithBroker( return false; } - return HandleExceptionWithConnection(&client, info, local_report_id); + return HandleExceptionWithConnection( + &client, info, 0, nullptr, local_report_id); } bool CrashReportExceptionHandler::HandleExceptionWithConnection( PtraceConnection* connection, const ClientInformation& info, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id, UUID* local_report_id) { ProcessSnapshotLinux process_snapshot; if (!process_snapshot.Initialize(connection)) { @@ -85,6 +95,11 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( return false; } + if (requesting_thread_id && requesting_thread_stack_address) { + *requesting_thread_id = process_snapshot.FindThreadWithStackAddress( + requesting_thread_stack_address); + } + if (!process_snapshot.InitializeException( info.exception_information_address)) { Metrics::ExceptionCaptureResult( diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index 9951d840..18051656 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -66,6 +66,8 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { bool HandleException(pid_t client_process_id, const ClientInformation& info, + VMAddress requesting_thread_stack_address = 0, + pid_t* requesting_thread_id = nullptr, UUID* local_report_id = nullptr) override; bool HandleExceptionWithBroker(pid_t client_process_id, @@ -76,6 +78,8 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { private: bool HandleExceptionWithConnection(PtraceConnection* connection, const ClientInformation& info, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id, UUID* local_report_id = nullptr); CrashReportDatabase* database_; // weak diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index 12e73635..c2842120 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -414,8 +414,10 @@ bool ExceptionHandlerServer::ReceiveClientMessage(Event* event) { switch (client_msg->type) { case ClientToServerMessage::kCrashDumpRequest: - return HandleCrashDumpRequest( - msg, client_msg->client_info, event->fd.get()); + return HandleCrashDumpRequest(msg, + client_msg->client_info, + client_msg->requesting_thread_stack_address, + event->fd.get()); } DCHECK(false); @@ -426,6 +428,7 @@ bool ExceptionHandlerServer::ReceiveClientMessage(Event* event) { bool ExceptionHandlerServer::HandleCrashDumpRequest( const msghdr& msg, const ClientInformation& client_info, + VMAddress requesting_thread_stack_address, int client_sock) { cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); if (cmsg == nullptr) { @@ -460,7 +463,8 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( ServerToClientMessage::kTypeCrashDumpFailed); case PtraceStrategyDecider::Strategy::kDirectPtrace: - delegate_->HandleException(client_process_id, client_info); + delegate_->HandleException( + client_process_id, client_info, requesting_thread_stack_address); break; case PtraceStrategyDecider::Strategy::kUseBroker: diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index 239aeea7..6f13fdc7 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -73,11 +73,19 @@ class ExceptionHandlerServer { //! //! \param[in] client_process_id The process ID of the crashing client. //! \param[in] info Information on the client. + //! \param[in] requesting_thread_stack_address Any address within the stack + //! range for the the thread that sent the crash dump request. Optional. + //! If unspecified or 0, \a requesting_thread_id will be -1. + //! \param[out] requesting_thread_id The thread ID of the thread which + //! requested the crash dump if not `nullptr`. Set to -1 if the thread + //! ID could not be determined. Optional. //! \param[out] local_report_id The unique identifier for the report created //! in the local report database. Optional. //! \return `true` on success. `false` on failure with a message logged. virtual bool HandleException(pid_t client_process_id, const ClientInformation& info, + VMAddress requesting_thread_stack_address = 0, + pid_t* requesting_thread_id = nullptr, UUID* local_report_id = nullptr) = 0; //! \brief Called on the receipt of a crash dump request from a client for a @@ -141,6 +149,7 @@ class ExceptionHandlerServer { bool ReceiveClientMessage(Event* event); bool HandleCrashDumpRequest(const msghdr& msg, const ClientInformation& client_info, + VMAddress requesting_thread_stack_address, int client_sock); std::unordered_map<int, std::unique_ptr<Event>> clients_; diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index 083a4ea5..7d15cbb9 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -19,6 +19,7 @@ #include "base/logging.h" #include "gtest/gtest.h" +#include "snapshot/linux/process_snapshot_linux.h" #include "test/errors.h" #include "test/multiprocess.h" #include "util/linux/direct_ptrace_connection.h" @@ -103,6 +104,8 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { bool HandleException(pid_t client_process_id, const ClientInformation& info, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id = nullptr, UUID* local_report_id = nullptr) override { DirectPtraceConnection connection; bool connected = connection.Initialize(client_process_id); @@ -111,7 +114,24 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { last_exception_address_ = info.exception_information_address; last_client_ = client_process_id; sem_.Signal(); - return connected; + if (!connected) { + return false; + } + + if (requesting_thread_id) { + if (requesting_thread_stack_address) { + ProcessSnapshotLinux process_snapshot; + if (!process_snapshot.Initialize(&connection)) { + ADD_FAILURE(); + return false; + } + *requesting_thread_id = process_snapshot.FindThreadWithStackAddress( + requesting_thread_stack_address); + } else { + *requesting_thread_id = -1; + } + } + return true; } bool HandleExceptionWithBroker(pid_t client_process_id, diff --git a/snapshot/linux/process_snapshot_linux.cc b/snapshot/linux/process_snapshot_linux.cc index 4141b2f4..3442e4af 100644 --- a/snapshot/linux/process_snapshot_linux.cc +++ b/snapshot/linux/process_snapshot_linux.cc @@ -49,6 +49,20 @@ bool ProcessSnapshotLinux::Initialize(PtraceConnection* connection) { return true; } +pid_t ProcessSnapshotLinux::FindThreadWithStackAddress( + VMAddress stack_address) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + for (const auto& thread : process_reader_.Threads()) { + if (stack_address >= thread.stack_region_address && + stack_address < + thread.stack_region_address + thread.stack_region_size) { + return thread.tid; + } + } + return -1; +} + bool ProcessSnapshotLinux::InitializeException( LinuxVMAddress exception_info_address) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); diff --git a/snapshot/linux/process_snapshot_linux.h b/snapshot/linux/process_snapshot_linux.h index 84bd226a..c96384d9 100644 --- a/snapshot/linux/process_snapshot_linux.h +++ b/snapshot/linux/process_snapshot_linux.h @@ -58,6 +58,13 @@ class ProcessSnapshotLinux final : public ProcessSnapshot { //! an appropriate message logged. bool Initialize(PtraceConnection* connection); + //! \brief Finds the thread whose stack contains \a stack_address. + //! + //! \param[in] stack_address A stack address to search for. + //! \return The thread ID of the thread whose stack contains \a stack_address + //! or -1 if no matching thread is found. + pid_t FindThreadWithStackAddress(VMAddress stack_address); + //! \brief Initializes the object's exception. //! //! \param[in] exception_info The address of an ExceptionInformation in the diff --git a/util/linux/exception_handler_client.cc b/util/linux/exception_handler_client.cc index 6333351c..e4548d62 100644 --- a/util/linux/exception_handler_client.cc +++ b/util/linux/exception_handler_client.cc @@ -25,6 +25,7 @@ #include "build/build_config.h" #include "util/file/file_io.h" #include "util/linux/ptrace_broker.h" +#include "util/misc/from_pointer_cast.h" #include "util/posix/signals.h" namespace crashpad { @@ -35,7 +36,9 @@ ExceptionHandlerClient::ExceptionHandlerClient(int sock) ExceptionHandlerClient::~ExceptionHandlerClient() = default; int ExceptionHandlerClient::RequestCrashDump(const ClientInformation& info) { - int status = SendCrashDumpRequest(info); + VMAddress sp = FromPointerCast<VMAddress>(&sp); + + int status = SendCrashDumpRequest(info, sp); if (status != 0) { return status; } @@ -61,10 +64,11 @@ void ExceptionHandlerClient::SetCanSetPtracer(bool can_set_ptracer) { can_set_ptracer_ = can_set_ptracer; } -int ExceptionHandlerClient::SendCrashDumpRequest( - const ClientInformation& info) { +int ExceptionHandlerClient::SendCrashDumpRequest(const ClientInformation& info, + VMAddress stack_pointer) { ClientToServerMessage message; message.type = ClientToServerMessage::kCrashDumpRequest; + message.requesting_thread_stack_address = stack_pointer; message.client_info = info; iovec iov; diff --git a/util/linux/exception_handler_client.h b/util/linux/exception_handler_client.h index a60b0656..25a8a442 100644 --- a/util/linux/exception_handler_client.h +++ b/util/linux/exception_handler_client.h @@ -53,7 +53,8 @@ class ExceptionHandlerClient { void SetCanSetPtracer(bool can_set_ptracer); private: - int SendCrashDumpRequest(const ClientInformation& info); + int SendCrashDumpRequest(const ClientInformation& info, + VMAddress stack_pointer); int WaitForCrashDumpComplete(); int server_sock_; diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index 4ba1b5d0..0ab3ffd0 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -57,6 +57,9 @@ struct ClientToServerMessage { //! \brief Indicates what message version is being used. int32_t version; + //! \brief A stack address of the thread sending the message. + VMAddress requesting_thread_stack_address; + enum Type : uint32_t { //! \brief Used to request a crash dump for the sending client. kCrashDumpRequest From a7859e9bc63e54e972906745cbcc1b8543a4fe10 Mon Sep 17 00:00:00 2001 From: Peter Wen <wnwen@chromium.org> Date: Wed, 17 Apr 2019 12:54:06 -0400 Subject: [PATCH 182/401] Add ExceptionSnapshotMinidump. Implemented all of the interface except Context(). Bug: crashpad:10 Change-Id: If76e539fd7b995da50f83e02f095f05537f5572a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1567489 Commit-Queue: Peter Wen <wnwen@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> Reviewed-by: Casey Dahlin <sadmac@google.com> --- snapshot/BUILD.gn | 2 + .../minidump/exception_snapshot_minidump.cc | 93 +++++++++++++++++++ .../minidump/exception_snapshot_minidump.h | 72 ++++++++++++++ .../minidump/process_snapshot_minidump.cc | 38 ++++++-- snapshot/minidump/process_snapshot_minidump.h | 6 ++ .../process_snapshot_minidump_test.cc | 77 +++++++++++++++ snapshot/snapshot.gyp | 2 + 7 files changed, 280 insertions(+), 10 deletions(-) create mode 100644 snapshot/minidump/exception_snapshot_minidump.cc create mode 100644 snapshot/minidump/exception_snapshot_minidump.h diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 89257140..17488a08 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -36,6 +36,8 @@ static_library("snapshot") { "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", diff --git a/snapshot/minidump/exception_snapshot_minidump.cc b/snapshot/minidump/exception_snapshot_minidump.cc new file mode 100644 index 00000000..0852ed90 --- /dev/null +++ b/snapshot/minidump/exception_snapshot_minidump.cc @@ -0,0 +1,93 @@ +// 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. + +#include "snapshot/minidump/exception_snapshot_minidump.h" + +#include "snapshot/minidump/minidump_string_reader.h" + +namespace crashpad { +namespace internal { + +ExceptionSnapshotMinidump::ExceptionSnapshotMinidump() + : ExceptionSnapshot(), + minidump_exception_stream_(), + exception_information_(), + initialized_() {} + +ExceptionSnapshotMinidump::~ExceptionSnapshotMinidump() {} + +bool ExceptionSnapshotMinidump::Initialize(FileReaderInterface* file_reader, + RVA minidump_exception_stream_rva) { + DCHECK(initialized_.is_uninitialized()); + initialized_.set_invalid(); + + if (!file_reader->SeekSet(minidump_exception_stream_rva)) { + return false; + } + + if (!file_reader->ReadExactly(&minidump_exception_stream_, + sizeof(minidump_exception_stream_))) { + return false; + } + + const size_t num_parameters = + minidump_exception_stream_.ExceptionRecord.NumberParameters; + for (size_t i = 0; i < num_parameters; ++i) { + exception_information_.push_back( + minidump_exception_stream_.ExceptionRecord.ExceptionInformation[i]); + } + + initialized_.set_valid(); + return true; +} + +const CPUContext* ExceptionSnapshotMinidump::Context() const { + DCHECK(initialized_.is_valid()); + NOTREACHED(); // https://crashpad.chromium.org/bug/10 + return nullptr; +} + +uint64_t ExceptionSnapshotMinidump::ThreadID() const { + DCHECK(initialized_.is_valid()); + return minidump_exception_stream_.ThreadId; +} + +uint32_t ExceptionSnapshotMinidump::Exception() const { + DCHECK(initialized_.is_valid()); + return minidump_exception_stream_.ExceptionRecord.ExceptionCode; +} + +uint32_t ExceptionSnapshotMinidump::ExceptionInfo() const { + DCHECK(initialized_.is_valid()); + return minidump_exception_stream_.ExceptionRecord.ExceptionFlags; +} + +uint64_t ExceptionSnapshotMinidump::ExceptionAddress() const { + DCHECK(initialized_.is_valid()); + return minidump_exception_stream_.ExceptionRecord.ExceptionAddress; +} + +const std::vector<uint64_t>& ExceptionSnapshotMinidump::Codes() const { + DCHECK(initialized_.is_valid()); + return exception_information_; +} + +std::vector<const MemorySnapshot*> ExceptionSnapshotMinidump::ExtraMemory() + const { + DCHECK(initialized_.is_valid()); + return std::vector<const MemorySnapshot*>(); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/minidump/exception_snapshot_minidump.h b/snapshot/minidump/exception_snapshot_minidump.h new file mode 100644 index 00000000..8ce29f7c --- /dev/null +++ b/snapshot/minidump/exception_snapshot_minidump.h @@ -0,0 +1,72 @@ +// 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_SNAPSHOT_MINIDUMP_EXCEPTION_SNAPSHOT_MINIDUMP_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_EXCEPTION_SNAPSHOT_MINIDUMP_H_ + +#include <windows.h> +#include <dbghelp.h> + +#include "build/build_config.h" +#include "snapshot/cpu_context.h" +#include "snapshot/exception_snapshot.h" +#include "util/file/file_reader.h" +#include "util/misc/initialization_state.h" + +namespace crashpad { +namespace internal { + +//! \brief An ExceptionSnapshot based on a minidump file. +class ExceptionSnapshotMinidump final : public ExceptionSnapshot { + public: + ExceptionSnapshotMinidump(); + ~ExceptionSnapshotMinidump() override; + + //! \brief Initializes the object. + //! + //! \param[in] file_reader A file reader corresponding to a minidump file. + //! The file reader must support seeking. + //! \param[in] minidump_exception_stream_rva The file offset in \a file_reader + //! at which the MINIDUMP_EXCEPTION_STREAM structure is located. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! an appropriate message logged. + bool Initialize(FileReaderInterface* file_reader, + RVA minidump_exception_stream_rva); + + // ExceptionSnapshot: + const CPUContext* Context() const override; + uint64_t ThreadID() const override; + uint32_t Exception() const override; + uint32_t ExceptionInfo() const override; + uint64_t ExceptionAddress() const override; + const std::vector<uint64_t>& Codes() const override; + std::vector<const MemorySnapshot*> ExtraMemory() const override; + + // Allow callers to explicitly check whether this exception snapshot has been + // initialized. + bool IsValid() const { return initialized_.is_valid(); } + + private: + MINIDUMP_EXCEPTION_STREAM minidump_exception_stream_; + std::vector<uint64_t> exception_information_; + InitializationState initialized_; + + DISALLOW_COPY_AND_ASSIGN(ExceptionSnapshotMinidump); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_EXCEPTION_SNAPSHOT_MINIDUMP_H_ diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 620f5de9..f191cb95 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -53,12 +53,12 @@ ProcessSnapshotMinidump::ProcessSnapshotMinidump() custom_streams_(), crashpad_info_(), system_snapshot_(), + exception_snapshot_(), arch_(CPUArchitecture::kCPUArchitectureUnknown), annotations_simple_map_(), file_reader_(nullptr), process_id_(static_cast<pid_t>(-1)), - initialized_() { -} + initialized_() {} ProcessSnapshotMinidump::~ProcessSnapshotMinidump() { } @@ -109,13 +109,10 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { stream_map_[stream_type] = &directory.Location; } - if (!InitializeCrashpadInfo() || - !InitializeMiscInfo() || - !InitializeModules() || - !InitializeSystemSnapshot() || - !InitializeMemoryInfo() || - !InitializeThreads() || - !InitializeCustomMinidumpStreams()) { + if (!InitializeCrashpadInfo() || !InitializeMiscInfo() || + !InitializeModules() || !InitializeSystemSnapshot() || + !InitializeMemoryInfo() || !InitializeThreads() || + !InitializeCustomMinidumpStreams() || !InitializeExceptionSnapshot()) { return false; } @@ -212,7 +209,10 @@ std::vector<UnloadedModuleSnapshot> ProcessSnapshotMinidump::UnloadedModules() const ExceptionSnapshot* ProcessSnapshotMinidump::Exception() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 + if (exception_snapshot_.IsValid()) { + return &exception_snapshot_; + } + // Allow caller to know whether the minidump contained an exception stream. return nullptr; } @@ -576,4 +576,22 @@ bool ProcessSnapshotMinidump::InitializeCustomMinidumpStreams() { return true; } +bool ProcessSnapshotMinidump::InitializeExceptionSnapshot() { + const auto& stream_it = stream_map_.find(kMinidumpStreamTypeException); + if (stream_it == stream_map_.end()) { + return true; + } + + if (stream_it->second->DataSize < sizeof(MINIDUMP_EXCEPTION_STREAM)) { + LOG(ERROR) << "system info size mismatch"; + return false; + } + + if (!exception_snapshot_.Initialize(file_reader_, stream_it->second->Rva)) { + return false; + } + + return true; +} + } // namespace crashpad diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 8653d33a..2df59d29 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -29,6 +29,7 @@ #include "minidump/minidump_extensions.h" #include "snapshot/exception_snapshot.h" #include "snapshot/memory_snapshot.h" +#include "snapshot/minidump/exception_snapshot_minidump.h" #include "snapshot/minidump/minidump_stream.h" #include "snapshot/minidump/module_snapshot_minidump.h" #include "snapshot/minidump/system_snapshot_minidump.h" @@ -129,6 +130,10 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { // Initializes custom minidump streams. bool InitializeCustomMinidumpStreams(); + // Initializes data carried in a MINIDUMP_EXCEPTION_STREAM stream on behalf of + // Initialize(). + bool InitializeExceptionSnapshot(); + MINIDUMP_HEADER header_; std::vector<MINIDUMP_DIRECTORY> stream_directory_; std::map<MinidumpStreamType, const MINIDUMP_LOCATION_DESCRIPTOR*> stream_map_; @@ -141,6 +146,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector<std::unique_ptr<MinidumpStream>> custom_streams_; MinidumpCrashpadInfo crashpad_info_; internal::SystemSnapshotMinidump system_snapshot_; + internal::ExceptionSnapshotMinidump exception_snapshot_; CPUArchitecture arch_; std::map<std::string, std::string> annotations_simple_map_; FileReaderInterface* file_reader_; // weak diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index f4b611d4..a03edfb1 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -1170,6 +1170,83 @@ TEST(ProcessSnapshotMinidump, CustomMinidumpStreams) { EXPECT_STREQ((char*)&stream_data.front(), kStreamUnreservedData); } +TEST(ProcessSnapshotMinidump, Exception) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + uint32_t exception_signo = + static_cast<uint32_t>(-1); // crashpad::Signals::kSimulatedSigno + + MINIDUMP_EXCEPTION minidump_exception = {}; + minidump_exception.ExceptionCode = exception_signo; + minidump_exception.ExceptionFlags = 2; + minidump_exception.ExceptionRecord = 4; + minidump_exception.ExceptionAddress = 0xdeedb00f; + minidump_exception.NumberParameters = 2; + minidump_exception.ExceptionInformation[0] = 51; + minidump_exception.ExceptionInformation[1] = 62; + + MINIDUMP_EXCEPTION_STREAM minidump_exception_stream = {}; + minidump_exception_stream.ThreadId = 5; + minidump_exception_stream.ExceptionRecord = minidump_exception; + + MINIDUMP_DIRECTORY minidump_exception_directory = {}; + minidump_exception_directory.StreamType = kMinidumpStreamTypeException; + minidump_exception_directory.Location.DataSize = + sizeof(MINIDUMP_EXCEPTION_STREAM); + minidump_exception_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + ASSERT_TRUE(string_file.Write(&minidump_exception_stream, + sizeof(minidump_exception_stream))); + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&minidump_exception_directory, + sizeof(minidump_exception_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + EXPECT_TRUE(string_file.SeekSet(0)); + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_TRUE(process_snapshot.Initialize(&string_file)); + + const ExceptionSnapshot* s = process_snapshot.Exception(); + + EXPECT_EQ(s->ThreadID(), 5UL); + EXPECT_EQ(s->Exception(), exception_signo); + EXPECT_EQ(s->ExceptionInfo(), 2U); + EXPECT_EQ(s->ExceptionAddress(), 0xdeedb00f); + + const std::vector<uint64_t> codes = s->Codes(); + EXPECT_EQ(codes.size(), 2UL); + EXPECT_EQ(codes[0], 51UL); + EXPECT_EQ(codes[1], 62UL); +} + +TEST(ProcessSnapshotMinidump, NoExceptionInMinidump) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 0; + EXPECT_TRUE(string_file.SeekSet(0)); + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_TRUE(process_snapshot.Initialize(&string_file)); + + const ExceptionSnapshot* s = process_snapshot.Exception(); + EXPECT_EQ(s, nullptr); +} + } // namespace } // namespace test } // namespace crashpad diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 8c563f52..0b4e157b 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -116,6 +116,8 @@ 'minidump/minidump_string_list_reader.h', 'minidump/minidump_string_reader.cc', 'minidump/minidump_string_reader.h', + 'minidump/exception_snapshot_minidump.cc', + 'minidump/exception_snapshot_minidump.h', 'minidump/memory_snapshot_minidump.cc', 'minidump/memory_snapshot_minidump.h', 'minidump/module_snapshot_minidump.cc', From 5f77cf41b62d9cc9c18809a097cf4d261965849b Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Wed, 17 Apr 2019 22:01:50 -0700 Subject: [PATCH 183/401] Add CodeViewRecordBuildId Until now we've been stuffing ELF debug symbol link information into a CodeViewPDB70. This has reached the limits of its usefulness. We now add a CodeViewRecord that can contain a proper ELF build ID. Change-Id: Ice52cb2a958a1b9031943f280d9054da02d2f17d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1574107 Commit-Queue: Casey Dahlin <sadmac@google.com> Reviewed-by: Mark Mentovai <mark@chromium.org> --- minidump/minidump_module_writer.cc | 84 ++++++-- minidump/minidump_module_writer.h | 23 ++- minidump/minidump_module_writer_test.cc | 194 ++++++++++++++++-- minidump/test/minidump_writable_test_util.cc | 88 +++++--- minidump/test/minidump_writable_test_util.h | 56 +++-- snapshot/elf/module_snapshot_elf.cc | 26 ++- snapshot/elf/module_snapshot_elf.h | 1 + snapshot/mac/module_snapshot_mac.cc | 13 +- snapshot/mac/module_snapshot_mac.h | 1 + snapshot/minidump/module_snapshot_minidump.cc | 109 +++++++--- snapshot/minidump/module_snapshot_minidump.h | 7 + .../process_snapshot_minidump_test.cc | 108 +++++++--- snapshot/module_snapshot.h | 15 ++ .../sanitized/module_snapshot_sanitized.cc | 4 + .../sanitized/module_snapshot_sanitized.h | 1 + snapshot/test/test_module_snapshot.cc | 10 +- snapshot/test/test_module_snapshot.h | 5 + snapshot/win/module_snapshot_win.cc | 8 +- snapshot/win/module_snapshot_win.h | 1 + util/misc/pdb_structures.cc | 1 + util/misc/pdb_structures.h | 28 ++- 21 files changed, 603 insertions(+), 180 deletions(-) diff --git a/minidump/minidump_module_writer.cc b/minidump/minidump_module_writer.cc index 305d37c4..6e533524 100644 --- a/minidump/minidump_module_writer.cc +++ b/minidump/minidump_module_writer.cc @@ -31,8 +31,7 @@ namespace crashpad { -MinidumpModuleCodeViewRecordWriter::~MinidumpModuleCodeViewRecordWriter() { -} +MinidumpModuleCodeViewRecordWriter::~MinidumpModuleCodeViewRecordWriter() {} namespace internal { @@ -45,8 +44,7 @@ MinidumpModuleCodeViewRecordPDBLinkWriter< template <typename CodeViewRecordType> MinidumpModuleCodeViewRecordPDBLinkWriter< - CodeViewRecordType>::~MinidumpModuleCodeViewRecordPDBLinkWriter() { -} + CodeViewRecordType>::~MinidumpModuleCodeViewRecordPDBLinkWriter() {} template <typename CodeViewRecordType> size_t @@ -82,8 +80,7 @@ template class internal::MinidumpModuleCodeViewRecordPDBLinkWriter< CodeViewRecordPDB20>; MinidumpModuleCodeViewRecordPDB20Writer:: - ~MinidumpModuleCodeViewRecordPDB20Writer() { -} + ~MinidumpModuleCodeViewRecordPDB20Writer() {} void MinidumpModuleCodeViewRecordPDB20Writer::SetTimestampAndAge( time_t timestamp, @@ -100,8 +97,7 @@ template class internal::MinidumpModuleCodeViewRecordPDBLinkWriter< CodeViewRecordPDB70>; MinidumpModuleCodeViewRecordPDB70Writer:: - ~MinidumpModuleCodeViewRecordPDB70Writer() { -} + ~MinidumpModuleCodeViewRecordPDB70Writer() {} void MinidumpModuleCodeViewRecordPDB70Writer::InitializeFromSnapshot( const ModuleSnapshot* module_snapshot) { @@ -115,15 +111,52 @@ void MinidumpModuleCodeViewRecordPDB70Writer::InitializeFromSnapshot( SetUUIDAndAge(uuid, age); } +MinidumpModuleCodeViewRecordBuildIDWriter:: + MinidumpModuleCodeViewRecordBuildIDWriter() + : MinidumpModuleCodeViewRecordWriter(), build_id_() {} + +MinidumpModuleCodeViewRecordBuildIDWriter:: + ~MinidumpModuleCodeViewRecordBuildIDWriter() {} + +size_t MinidumpModuleCodeViewRecordBuildIDWriter::SizeOfObject() { + DCHECK_GE(state(), kStateFrozen); + return offsetof(CodeViewRecordBuildID, build_id) + build_id_.size(); +} + +void MinidumpModuleCodeViewRecordBuildIDWriter::SetBuildID( + const std::vector<uint8_t>& build_id) { + DCHECK_EQ(state(), kStateMutable); + build_id_ = build_id; +} + +bool MinidumpModuleCodeViewRecordBuildIDWriter::WriteObject( + FileWriterInterface* file_writer) { + DCHECK_EQ(state(), kStateWritable); + + CodeViewRecordBuildID cv; + cv.signature = CodeViewRecordBuildID::kSignature; + + WritableIoVec iov; + iov.iov_base = &cv; + iov.iov_len = offsetof(CodeViewRecordBuildID, build_id); + std::vector<WritableIoVec> iovecs(1, iov); + + if (!build_id_.empty()) { + iov.iov_base = build_id_.data(); + iov.iov_len = build_id_.size(); + iovecs.push_back(iov); + } + + return file_writer->WriteIoVec(&iovecs); +} + MinidumpModuleMiscDebugRecordWriter::MinidumpModuleMiscDebugRecordWriter() : internal::MinidumpWritable(), image_debug_misc_(), data_(), - data_utf16_() { -} + data_utf16_() {} -MinidumpModuleMiscDebugRecordWriter::~MinidumpModuleMiscDebugRecordWriter() { -} +MinidumpModuleMiscDebugRecordWriter::~MinidumpModuleMiscDebugRecordWriter() {} void MinidumpModuleMiscDebugRecordWriter::SetData(const std::string& data, bool utf16) { @@ -203,8 +236,7 @@ MinidumpModuleWriter::MinidumpModuleWriter() module_.VersionInfo.dwStrucVersion = VS_FFI_STRUCVERSION; } -MinidumpModuleWriter::~MinidumpModuleWriter() { -} +MinidumpModuleWriter::~MinidumpModuleWriter() {} void MinidumpModuleWriter::InitializeFromSnapshot( const ModuleSnapshot* module_snapshot) { @@ -242,9 +274,21 @@ void MinidumpModuleWriter::InitializeFromSnapshot( } SetFileTypeAndSubtype(file_type, VFT2_UNKNOWN); - auto codeview_record = - std::make_unique<MinidumpModuleCodeViewRecordPDB70Writer>(); - codeview_record->InitializeFromSnapshot(module_snapshot); + auto build_id = module_snapshot->BuildID(); + + std::unique_ptr<MinidumpModuleCodeViewRecordWriter> codeview_record; + if (!build_id.empty()) { + auto cv_record_build_id = + std::make_unique<MinidumpModuleCodeViewRecordBuildIDWriter>(); + cv_record_build_id->SetBuildID(build_id); + codeview_record = std::move(cv_record_build_id); + } else { + auto cv_record_pdb70 = + std::make_unique<MinidumpModuleCodeViewRecordPDB70Writer>(); + cv_record_pdb70->InitializeFromSnapshot(module_snapshot); + codeview_record = std::move(cv_record_pdb70); + } + SetCodeViewRecord(std::move(codeview_record)); } @@ -372,11 +416,9 @@ bool MinidumpModuleWriter::WriteObject(FileWriterInterface* file_writer) { } MinidumpModuleListWriter::MinidumpModuleListWriter() - : MinidumpStreamWriter(), modules_(), module_list_base_() { -} + : MinidumpStreamWriter(), modules_(), module_list_base_() {} -MinidumpModuleListWriter::~MinidumpModuleListWriter() { -} +MinidumpModuleListWriter::~MinidumpModuleListWriter() {} void MinidumpModuleListWriter::InitializeFromSnapshot( const std::vector<const ModuleSnapshot*>& module_snapshots) { diff --git a/minidump/minidump_module_writer.h b/minidump/minidump_module_writer.h index 555c4115..b328bf04 100644 --- a/minidump/minidump_module_writer.h +++ b/minidump/minidump_module_writer.h @@ -88,7 +88,8 @@ class MinidumpModuleCodeViewRecordPDBLinkWriter //! \brief The writer for a CodeViewRecordPDB20 object in a minidump file. //! -//! Most users will want MinidumpModuleCodeViewRecordPDB70Writer instead. +//! Most users will want MinidumpModuleCodeViewRecordPDB70Writer or +//! MinidumpModuleCodeViewRecordBuildIDWriter instead. class MinidumpModuleCodeViewRecordPDB20Writer final : public internal::MinidumpModuleCodeViewRecordPDBLinkWriter< CodeViewRecordPDB20> { @@ -136,6 +137,26 @@ class MinidumpModuleCodeViewRecordPDB70Writer final DISALLOW_COPY_AND_ASSIGN(MinidumpModuleCodeViewRecordPDB70Writer); }; +//! \brief The writer for a CodeViewRecordBuildID object in a minidump file. +class MinidumpModuleCodeViewRecordBuildIDWriter final + : public MinidumpModuleCodeViewRecordWriter { + public: + MinidumpModuleCodeViewRecordBuildIDWriter(); + ~MinidumpModuleCodeViewRecordBuildIDWriter() override; + + //! \brief Sets the build ID used for symbol lookup. + void SetBuildID(const std::vector<uint8_t>& build_id); + + private: + // MinidumpWritable: + size_t SizeOfObject() override; + bool WriteObject(FileWriterInterface* file_writer) override; + + std::vector<uint8_t> build_id_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpModuleCodeViewRecordBuildIDWriter); +}; + //! \brief The writer for an IMAGE_DEBUG_MISC object in a minidump file. //! //! Most users will want MinidumpModuleCodeViewRecordPDB70Writer instead. diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc index 8b5fc062..71db3ac1 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -265,6 +265,61 @@ void ExpectModule(const MINIDUMP_MODULE* expected, expected_debug_utf16)); } +// ExpectModuleWithBuildIDCv() is like ExpectModule( but expects the module to +// have a BuildID CodeView Record. +void ExpectModuleWithBuildIDCv(const MINIDUMP_MODULE* expected, + const MINIDUMP_MODULE* observed, + const std::string& file_contents, + const std::string& expected_module_name, + const std::vector<uint8_t>& expected_build_id) { + 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, + implicit_cast<uint32_t>(VS_FFI_SIGNATURE)); + EXPECT_EQ(observed->VersionInfo.dwStrucVersion, + implicit_cast<uint32_t>(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); + base::string16 observed_module_name_utf16 = + MinidumpStringAtRVAAsString(file_contents, observed->ModuleNameRva); + base::string16 expected_module_name_utf16 = + base::UTF8ToUTF16(expected_module_name); + EXPECT_EQ(observed_module_name_utf16, expected_module_name_utf16); + + const CodeViewRecordBuildID* codeview_build_id_record = + MinidumpWritableAtLocationDescriptor<CodeViewRecordBuildID>( + file_contents, observed->CvRecord); + ASSERT_TRUE(codeview_build_id_record); + EXPECT_EQ(memcmp(expected_build_id.data(), + &codeview_build_id_record->build_id, + expected_build_id.size()), + 0); +} + TEST(MinidumpModuleWriter, EmptyModule) { MinidumpFileWriter minidump_file_writer; auto module_list_writer = std::make_unique<MinidumpModuleListWriter>(); @@ -325,9 +380,22 @@ TEST(MinidumpModuleWriter, OneModule) { constexpr uint32_t kFileType = VFT_DRV; constexpr uint32_t kFileSubtype = VFT2_DRV_KEYBOARD; static constexpr char kPDBName[] = "statical.pdb"; - static constexpr uint8_t kPDBUUIDBytes[16] = - {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, - 0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f}; + static constexpr uint8_t kPDBUUIDBytes[16] = {0xfe, + 0xdc, + 0xba, + 0x98, + 0x76, + 0x54, + 0x32, + 0x10, + 0x08, + 0x19, + 0x2a, + 0x3b, + 0x4c, + 0x5d, + 0x6e, + 0x7f}; UUID pdb_uuid; pdb_uuid.InitializeFromBytes(kPDBUUIDBytes); constexpr uint32_t kPDBAge = 1; @@ -471,6 +539,50 @@ TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) { kDebugUTF16)); } +TEST(MinidumpModuleWriter, OneModule_CodeViewBuildID) { + // MinidumpModuleWriter.OneModule tested with a BuildID CodeView + MinidumpFileWriter minidump_file_writer; + auto module_list_writer = std::make_unique<MinidumpModuleListWriter>(); + + static constexpr char kModuleName[] = "dinosaur"; + static constexpr char kBuildID[] = + "averylonghashcodeormaybeitsjustrandomnumbershardtosay"; + + std::vector<uint8_t> build_id_data(kBuildID, kBuildID + 53); + + auto module_writer = std::make_unique<MinidumpModuleWriter>(); + module_writer->SetName(kModuleName); + + auto codeview_build_id_writer = + std::make_unique<MinidumpModuleCodeViewRecordBuildIDWriter>(); + codeview_build_id_writer->SetBuildID(build_id_data); + module_writer->SetCodeViewRecord(std::move(codeview_build_id_writer)); + + module_list_writer->AddModule(std::move(module_writer)); + ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_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_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE)); + + const MINIDUMP_MODULE_LIST* module_list = nullptr; + ASSERT_NO_FATAL_FAILURE( + GetModuleListStream(string_file.string(), &module_list)); + + EXPECT_EQ(module_list->NumberOfModules, 1u); + + MINIDUMP_MODULE expected = {}; + + ASSERT_NO_FATAL_FAILURE(ExpectModuleWithBuildIDCv(&expected, + &module_list->Modules[0], + string_file.string(), + kModuleName, + build_id_data)); +} + TEST(MinidumpModuleWriter, ThreeModules) { // As good exercise, this test uses three modules, one with a PDB 7.0 link as // its CodeView record, one with no CodeView record, and one with a PDB 2.0 @@ -482,9 +594,22 @@ TEST(MinidumpModuleWriter, ThreeModules) { constexpr uint64_t kModuleBase0 = 0x100101000; constexpr uint32_t kModuleSize0 = 0xf000; static constexpr char kPDBName0[] = "main"; - static constexpr uint8_t kPDBUUIDBytes0[16] = - {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, - 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}; + static constexpr uint8_t kPDBUUIDBytes0[16] = {0xaa, + 0xbb, + 0xcc, + 0xdd, + 0xee, + 0xff, + 0x00, + 0x11, + 0x22, + 0x33, + 0x44, + 0x55, + 0x66, + 0x77, + 0x88, + 0x99}; UUID pdb_uuid_0; pdb_uuid_0.InitializeFromBytes(kPDBUUIDBytes0); constexpr uint32_t kPDBAge0 = 0; @@ -666,9 +791,22 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { expect_modules[0].VersionInfo.dwFileType = VFT_APP; module_paths[0] = "/usr/bin/true"; module_pdbs[0] = "true"; - static constexpr uint8_t kUUIDBytes0[16] = - {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; + static constexpr uint8_t kUUIDBytes0[16] = {0x00, + 0x11, + 0x22, + 0x33, + 0x44, + 0x55, + 0x66, + 0x77, + 0x88, + 0x99, + 0xaa, + 0xbb, + 0xcc, + 0xdd, + 0xee, + 0xff}; uuids[0].InitializeFromBytes(kUUIDBytes0); ages[0] = 10; @@ -682,9 +820,22 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { expect_modules[1].VersionInfo.dwFileType = VFT_DLL; module_paths[1] = "/usr/lib/libSystem.B.dylib"; module_pdbs[1] = "libSystem.B.dylib.pdb"; - static constexpr uint8_t kUUIDBytes1[16] = - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + static constexpr uint8_t kUUIDBytes1[16] = {0x00, + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0a, + 0x0b, + 0x0c, + 0x0d, + 0x0e, + 0x0f}; uuids[1].InitializeFromBytes(kUUIDBytes1); ages[1] = 20; @@ -698,9 +849,22 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) { expect_modules[2].VersionInfo.dwFileType = VFT_UNKNOWN; module_paths[2] = "/usr/lib/dyld"; module_pdbs[2] = "/usr/lib/dyld.pdb"; - static constexpr uint8_t kUUIDBytes2[16] = - {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, - 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0}; + static constexpr uint8_t kUUIDBytes2[16] = {0xff, + 0xfe, + 0xfd, + 0xfc, + 0xfb, + 0xfa, + 0xf9, + 0xf8, + 0xf7, + 0xf6, + 0xf5, + 0xf4, + 0xf3, + 0xf2, + 0xf1, + 0xf0}; uuids[2].InitializeFromBytes(kUUIDBytes2); ages[2] = 30; diff --git a/minidump/test/minidump_writable_test_util.cc b/minidump/test/minidump_writable_test_util.cc index 1a832bf3..db07b366 100644 --- a/minidump/test/minidump_writable_test_util.cc +++ b/minidump/test/minidump_writable_test_util.cc @@ -210,17 +210,13 @@ struct MinidumpMemoryInfoListTraits { struct MinidumpModuleCrashpadInfoListTraits { using ListType = MinidumpModuleCrashpadInfoList; enum : size_t { kElementSize = sizeof(MinidumpModuleCrashpadInfoLink) }; - static size_t ElementCount(const ListType* list) { - return list->count; - } + static size_t ElementCount(const ListType* list) { return list->count; } }; struct MinidumpSimpleStringDictionaryListTraits { using ListType = MinidumpSimpleStringDictionary; enum : size_t { kElementSize = sizeof(MinidumpSimpleStringDictionaryEntry) }; - static size_t ElementCount(const ListType* list) { - return list->count; - } + static size_t ElementCount(const ListType* list) { return list->count; } }; struct MinidumpAnnotationListObjectsTraits { @@ -253,17 +249,19 @@ const typename T::ListType* MinidumpListAtLocationDescriptor( } // namespace template <> -const MINIDUMP_MEMORY_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MEMORY_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_MEMORY_LIST* +MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor<MinidumpMemoryListTraits>( file_contents, location); } template <> -const MINIDUMP_MODULE_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MODULE_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_MODULE_LIST* +MinidumpWritableAtLocationDescriptor<MINIDUMP_MODULE_LIST>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor<MinidumpModuleListTraits>( file_contents, location); } @@ -278,25 +276,28 @@ MinidumpWritableAtLocationDescriptor<MINIDUMP_UNLOADED_MODULE_LIST>( } template <> -const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_THREAD_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_THREAD_LIST* +MinidumpWritableAtLocationDescriptor<MINIDUMP_THREAD_LIST>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor<MinidumpThreadListTraits>( file_contents, location); } template <> -const MINIDUMP_HANDLE_DATA_STREAM* MinidumpWritableAtLocationDescriptor< - MINIDUMP_HANDLE_DATA_STREAM>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_HANDLE_DATA_STREAM* +MinidumpWritableAtLocationDescriptor<MINIDUMP_HANDLE_DATA_STREAM>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor<MinidumpHandleDataStreamTraits>( file_contents, location); } template <> -const MINIDUMP_MEMORY_INFO_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MEMORY_INFO_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_MEMORY_INFO_LIST* +MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_INFO_LIST>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor<MinidumpMemoryInfoListTraits>( file_contents, location); } @@ -357,28 +358,51 @@ const T* MinidumpCVPDBAtLocationDescriptor( } // namespace template <> -const CodeViewRecordPDB20* MinidumpWritableAtLocationDescriptor< - CodeViewRecordPDB20>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const CodeViewRecordPDB20* +MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB20>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpCVPDBAtLocationDescriptor<CodeViewRecordPDB20>(file_contents, location); } template <> -const CodeViewRecordPDB70* MinidumpWritableAtLocationDescriptor< - CodeViewRecordPDB70>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const CodeViewRecordPDB70* +MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB70>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpCVPDBAtLocationDescriptor<CodeViewRecordPDB70>(file_contents, location); } -TestUInt32MinidumpWritable::TestUInt32MinidumpWritable(uint32_t value) - : MinidumpWritable(), - value_(value) { +template <> +const CodeViewRecordBuildID* +MinidumpWritableAtLocationDescriptor<CodeViewRecordBuildID>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + const CodeViewRecordBuildID* cv = + reinterpret_cast<const CodeViewRecordBuildID*>( + MinidumpWritableAtLocationDescriptorInternal( + file_contents, + location, + offsetof(CodeViewRecordBuildID, build_id), + true)); + + if (!cv) { + return nullptr; + } + + if (cv->signature != CodeViewRecordBuildID::kSignature) { + return nullptr; + } + + return cv; } -TestUInt32MinidumpWritable::~TestUInt32MinidumpWritable() { -} +TestUInt32MinidumpWritable::TestUInt32MinidumpWritable(uint32_t value) + : MinidumpWritable(), value_(value) {} + +TestUInt32MinidumpWritable::~TestUInt32MinidumpWritable() {} size_t TestUInt32MinidumpWritable::SizeOfObject() { return sizeof(value_); diff --git a/minidump/test/minidump_writable_test_util.h b/minidump/test/minidump_writable_test_util.h index 5b176d2b..6c706fba 100644 --- a/minidump/test/minidump_writable_test_util.h +++ b/minidump/test/minidump_writable_test_util.h @@ -104,6 +104,7 @@ MINIDUMP_ALLOW_OVERSIZED_DATA(IMAGE_DEBUG_MISC); MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_STRING); MINIDUMP_ALLOW_OVERSIZED_DATA(CodeViewRecordPDB20); MINIDUMP_ALLOW_OVERSIZED_DATA(CodeViewRecordPDB70); +MINIDUMP_ALLOW_OVERSIZED_DATA(CodeViewRecordBuildID); MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpUTF8String); // minidump_file_writer_test accesses its variable-sized test streams via a @@ -179,14 +180,16 @@ const MINIDUMP_HEADER* MinidumpWritableAtLocationDescriptor<MINIDUMP_HEADER>( const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const MINIDUMP_MEMORY_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MEMORY_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const MINIDUMP_MEMORY_LIST* +MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const MINIDUMP_MODULE_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MODULE_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const MINIDUMP_MODULE_LIST* +MinidumpWritableAtLocationDescriptor<MINIDUMP_MODULE_LIST>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> const MINIDUMP_UNLOADED_MODULE_LIST* @@ -195,29 +198,40 @@ MinidumpWritableAtLocationDescriptor<MINIDUMP_UNLOADED_MODULE_LIST>( const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_THREAD_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const MINIDUMP_THREAD_LIST* +MinidumpWritableAtLocationDescriptor<MINIDUMP_THREAD_LIST>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const MINIDUMP_HANDLE_DATA_STREAM* MinidumpWritableAtLocationDescriptor< - MINIDUMP_HANDLE_DATA_STREAM>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const MINIDUMP_HANDLE_DATA_STREAM* +MinidumpWritableAtLocationDescriptor<MINIDUMP_HANDLE_DATA_STREAM>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const MINIDUMP_MEMORY_INFO_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MEMORY_INFO_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const MINIDUMP_MEMORY_INFO_LIST* +MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_INFO_LIST>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const CodeViewRecordPDB20* MinidumpWritableAtLocationDescriptor< - CodeViewRecordPDB20>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const CodeViewRecordPDB20* +MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB20>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const CodeViewRecordPDB70* MinidumpWritableAtLocationDescriptor< - CodeViewRecordPDB70>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const CodeViewRecordPDB70* +MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB70>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); + +template <> +const CodeViewRecordBuildID* +MinidumpWritableAtLocationDescriptor<CodeViewRecordBuildID>( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> const MinidumpModuleCrashpadInfoList* diff --git a/snapshot/elf/module_snapshot_elf.cc b/snapshot/elf/module_snapshot_elf.cc index 39385a6d..cfe07dd4 100644 --- a/snapshot/elf/module_snapshot_elf.cc +++ b/snapshot/elf/module_snapshot_elf.cc @@ -150,13 +150,10 @@ void ModuleSnapshotElf::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); *age = 0; - std::unique_ptr<ElfImageReader::NoteReader> notes = - elf_reader_->NotesWithNameAndType(ELF_NOTE_GNU, NT_GNU_BUILD_ID, 64); - std::string desc; - VMAddress desc_addr; - notes->NextNote(nullptr, nullptr, &desc, &desc_addr); - desc.insert(desc.end(), 16 - std::min(desc.size(), size_t{16}), '\0'); - uuid->InitializeFromBytes(reinterpret_cast<const uint8_t*>(&desc[0])); + auto build_id = BuildID(); + build_id.insert( + build_id.end(), 16 - std::min(build_id.size(), size_t{16}), '\0'); + uuid->InitializeFromBytes(build_id.data()); // TODO(scottmg): https://crashpad.chromium.org/bug/229. These are // endian-swapped to match FileID::ConvertIdentifierToUUIDString() in @@ -171,6 +168,21 @@ std::string ModuleSnapshotElf::DebugFileName() const { return base::FilePath(Name()).BaseName().value(); } +std::vector<uint8_t> ModuleSnapshotElf::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + std::unique_ptr<ElfImageReader::NoteReader> notes = + elf_reader_->NotesWithNameAndType(ELF_NOTE_GNU, NT_GNU_BUILD_ID, 64); + std::string desc; + VMAddress desc_addr; + notes->NextNote(nullptr, nullptr, &desc, &desc_addr); + + std::vector<uint8_t> build_id; + build_id.reserve(desc.size()); + std::copy(desc.begin(), desc.end(), std::back_inserter(build_id)); + return build_id; +} + std::vector<std::string> ModuleSnapshotElf::AnnotationsVector() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return std::vector<std::string>(); diff --git a/snapshot/elf/module_snapshot_elf.h b/snapshot/elf/module_snapshot_elf.h index 15c3f3c2..be27242f 100644 --- a/snapshot/elf/module_snapshot_elf.h +++ b/snapshot/elf/module_snapshot_elf.h @@ -77,6 +77,7 @@ class ModuleSnapshotElf final : public ModuleSnapshot { ModuleType GetModuleType() const override; void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override; std::string DebugFileName() const override; + std::vector<uint8_t> BuildID() const override; std::vector<std::string> AnnotationsVector() const override; std::map<std::string, std::string> AnnotationsSimpleMap() const override; std::vector<AnnotationSnapshot> AnnotationObjects() const override; diff --git a/snapshot/mac/module_snapshot_mac.cc b/snapshot/mac/module_snapshot_mac.cc index 41608978..947744db 100644 --- a/snapshot/mac/module_snapshot_mac.cc +++ b/snapshot/mac/module_snapshot_mac.cc @@ -14,8 +14,8 @@ #include "snapshot/mac/module_snapshot_mac.h" -#include <mach/mach.h> #include <mach-o/loader.h> +#include <mach/mach.h> #include "base/files/file_path.h" #include "base/strings/stringprintf.h" @@ -34,11 +34,9 @@ ModuleSnapshotMac::ModuleSnapshotMac() timestamp_(0), mach_o_image_reader_(nullptr), process_reader_(nullptr), - initialized_() { -} + initialized_() {} -ModuleSnapshotMac::~ModuleSnapshotMac() { -} +ModuleSnapshotMac::~ModuleSnapshotMac() {} bool ModuleSnapshotMac::Initialize( ProcessReaderMac* process_reader, @@ -170,6 +168,11 @@ std::string ModuleSnapshotMac::DebugFileName() const { return base::FilePath(Name()).BaseName().value(); } +std::vector<uint8_t> ModuleSnapshotMac::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<uint8_t>(); +} + std::vector<std::string> ModuleSnapshotMac::AnnotationsVector() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); MachOImageAnnotationsReader annotations_reader( diff --git a/snapshot/mac/module_snapshot_mac.h b/snapshot/mac/module_snapshot_mac.h index fe2d40a1..d78c3266 100644 --- a/snapshot/mac/module_snapshot_mac.h +++ b/snapshot/mac/module_snapshot_mac.h @@ -77,6 +77,7 @@ class ModuleSnapshotMac final : public ModuleSnapshot { ModuleType GetModuleType() const override; void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override; std::string DebugFileName() const override; + std::vector<uint8_t> BuildID() const override; std::vector<std::string> AnnotationsVector() const override; std::map<std::string, std::string> AnnotationsSimpleMap() const override; std::vector<AnnotationSnapshot> AnnotationObjects() const override; diff --git a/snapshot/minidump/module_snapshot_minidump.cc b/snapshot/minidump/module_snapshot_minidump.cc index b3e33d04..a316e83b 100644 --- a/snapshot/minidump/module_snapshot_minidump.cc +++ b/snapshot/minidump/module_snapshot_minidump.cc @@ -14,13 +14,15 @@ #include "snapshot/minidump/module_snapshot_minidump.h" +#include <stddef.h> #include <string.h> +#include "base/logging.h" #include "minidump/minidump_extensions.h" #include "snapshot/minidump/minidump_annotation_reader.h" -#include "snapshot/minidump/minidump_string_reader.h" #include "snapshot/minidump/minidump_simple_string_dictionary_reader.h" #include "snapshot/minidump/minidump_string_list_reader.h" +#include "snapshot/minidump/minidump_string_reader.h" #include "util/misc/pdb_structures.h" namespace crashpad { @@ -33,13 +35,13 @@ ModuleSnapshotMinidump::ModuleSnapshotMinidump() annotations_simple_map_(), annotation_objects_(), uuid_(), + build_id_(), name_(), + debug_file_name_(), age_(0), - initialized_() { -} + initialized_() {} -ModuleSnapshotMinidump::~ModuleSnapshotMinidump() { -} +ModuleSnapshotMinidump::~ModuleSnapshotMinidump() {} bool ModuleSnapshotMinidump::Initialize( FileReaderInterface* file_reader, @@ -63,33 +65,68 @@ bool ModuleSnapshotMinidump::Initialize( ReadMinidumpUTF16String(file_reader, minidump_module_.ModuleNameRva, &name_); - if (minidump_module_.CvRecord.Rva != 0) { - CodeViewRecordPDB70 cv; - - if (!file_reader->SeekSet(minidump_module_.CvRecord.Rva)) { - return false; - } - - if (!file_reader->ReadExactly(&cv, sizeof(cv))) { - return false; - } - - if (cv.signature == 'SDSR') { - age_ = cv.age; - uuid_ = cv.uuid; - } else if (cv.signature != '01BN') { - LOG(ERROR) << "Bad CodeView signature in module"; - return false; - } else { - LOG(ERROR) << "NB10 not supported"; - return false; - } + if (minidump_module_.CvRecord.Rva != 0 && + !InitializeModuleCodeView(file_reader)) { + return false; } INITIALIZATION_STATE_SET_VALID(initialized_); return true; } +bool ModuleSnapshotMinidump::InitializeModuleCodeView( + FileReaderInterface* file_reader) { + uint32_t signature; + + DCHECK_NE(minidump_module_.CvRecord.Rva, 0u); + + if (minidump_module_.CvRecord.DataSize < sizeof(signature)) { + LOG(ERROR) << "CodeView record in module too small to contain signature"; + return false; + } + + if (!file_reader->SeekSet(minidump_module_.CvRecord.Rva)) { + return false; + } + + std::vector<uint8_t> cv_record; + cv_record.resize(minidump_module_.CvRecord.DataSize); + + if (!file_reader->ReadExactly(cv_record.data(), cv_record.size())) { + return false; + } + + signature = *reinterpret_cast<uint32_t*>(cv_record.data()); + + if (signature == CodeViewRecordPDB70::kSignature) { + if (cv_record.size() < offsetof(CodeViewRecordPDB70, pdb_name)) { + LOG(ERROR) << "CodeView record in module marked as PDB70 but too small"; + return false; + } + + auto cv_record_pdb70 = + reinterpret_cast<CodeViewRecordPDB70*>(cv_record.data()); + + age_ = cv_record_pdb70->age; + uuid_ = cv_record_pdb70->uuid; + + std::copy(cv_record.begin() + offsetof(CodeViewRecordPDB70, pdb_name), + cv_record.end(), + std::back_inserter(debug_file_name_)); + return true; + } + + if (signature == CodeViewRecordBuildID::kSignature) { + std::copy(cv_record.begin() + offsetof(CodeViewRecordBuildID, build_id), + cv_record.end(), + std::back_inserter(build_id_)); + return true; + } + + LOG(ERROR) << "Bad CodeView signature in module"; + return false; +} + std::string ModuleSnapshotMinidump::Name() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return name_; @@ -138,10 +175,10 @@ void ModuleSnapshotMinidump::SourceVersion(uint16_t* version_0, ModuleSnapshot::ModuleType ModuleSnapshotMinidump::GetModuleType() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); switch (minidump_module_.VersionInfo.dwFileType) { - case VFT_APP: - return kModuleTypeExecutable; - case VFT_DLL: - return kModuleTypeSharedLibrary; + case VFT_APP: + return kModuleTypeExecutable; + case VFT_DLL: + return kModuleTypeSharedLibrary; } return kModuleTypeUnknown; } @@ -155,8 +192,12 @@ void ModuleSnapshotMinidump::UUIDAndAge(crashpad::UUID* uuid, std::string ModuleSnapshotMinidump::DebugFileName() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return std::string(); + return debug_file_name_; +} + +std::vector<uint8_t> ModuleSnapshotMinidump::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return build_id_; } std::vector<std::string> ModuleSnapshotMinidump::AnnotationsVector() const { @@ -201,7 +242,7 @@ bool ModuleSnapshotMinidump::InitializeModuleCrashpadInfo( MinidumpModuleCrashpadInfo minidump_module_crashpad_info; if (minidump_module_crashpad_info_location->DataSize < - sizeof(minidump_module_crashpad_info)) { + sizeof(minidump_module_crashpad_info)) { LOG(ERROR) << "minidump_module_crashpad_info size mismatch"; return false; } @@ -216,7 +257,7 @@ bool ModuleSnapshotMinidump::InitializeModuleCrashpadInfo( } if (minidump_module_crashpad_info.version != - MinidumpModuleCrashpadInfo::kVersion) { + MinidumpModuleCrashpadInfo::kVersion) { LOG(ERROR) << "minidump_module_crashpad_info version mismatch"; return false; } diff --git a/snapshot/minidump/module_snapshot_minidump.h b/snapshot/minidump/module_snapshot_minidump.h index e6e50c51..023d0d59 100644 --- a/snapshot/minidump/module_snapshot_minidump.h +++ b/snapshot/minidump/module_snapshot_minidump.h @@ -75,6 +75,7 @@ class ModuleSnapshotMinidump final : public ModuleSnapshot { ModuleType GetModuleType() const override; void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override; std::string DebugFileName() const override; + std::vector<uint8_t> BuildID() const override; std::vector<std::string> AnnotationsVector() const override; std::map<std::string, std::string> AnnotationsSimpleMap() const override; std::vector<AnnotationSnapshot> AnnotationObjects() const override; @@ -88,12 +89,18 @@ class ModuleSnapshotMinidump final : public ModuleSnapshot { const MINIDUMP_LOCATION_DESCRIPTOR* minidump_module_crashpad_info_location); + // Initializes data from the CodeView record, which usually points toward + // debug symbols. + bool InitializeModuleCodeView(FileReaderInterface* file_reader); + MINIDUMP_MODULE minidump_module_; std::vector<std::string> annotations_vector_; std::map<std::string, std::string> annotations_simple_map_; std::vector<AnnotationSnapshot> annotation_objects_; UUID uuid_; + std::vector<uint8_t> build_id_; std::string name_; + std::string debug_file_name_; uint32_t age_; InitializationStateDcheck initialized_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index a03edfb1..7d5d16d3 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -307,10 +307,10 @@ TEST(ProcessSnapshotMinidump, Modules) { constexpr uint32_t minidump_module_count = 4; RVA name_rvas[minidump_module_count]; std::string names[minidump_module_count] = { - "libtacotruck", - "libevidencebased", - "libgeorgism", - "librealistutopia", + "libtacotruck", + "libevidencebased", + "libgeorgism", + "librealistutopia", }; minidump_module.BaseOfImage = 0xbadf00d; @@ -331,16 +331,28 @@ TEST(ProcessSnapshotMinidump, Modules) { EXPECT_TRUE(string_file.Write(&name16[0], size)); } - CodeViewRecordPDB70 cv; - cv.signature = CodeViewRecordPDB70::kSignature; - cv.age = 7; - cv.uuid.InitializeFromString("00112233-4455-6677-8899-aabbccddeeff"); - cv.pdb_name[0] = '\0'; + CodeViewRecordPDB70 pdb70_cv; + pdb70_cv.signature = CodeViewRecordPDB70::kSignature; + pdb70_cv.age = 7; + pdb70_cv.uuid.InitializeFromString("00112233-4455-6677-8899-aabbccddeeff"); + pdb70_cv.pdb_name[0] = '\0'; - minidump_module.CvRecord.Rva = static_cast<RVA>(string_file.SeekGet()); - minidump_module.CvRecord.DataSize = sizeof(cv); + auto pdb70_loc = static_cast<RVA>(string_file.SeekGet()); + auto pdb70_size = sizeof(pdb70_cv); - EXPECT_TRUE(string_file.Write(&cv, sizeof(cv))); + EXPECT_TRUE(string_file.Write(&pdb70_cv, sizeof(pdb70_cv))); + + CodeViewRecordBuildID build_id_cv; + build_id_cv.signature = CodeViewRecordBuildID::kSignature; + + auto build_id_cv_loc = static_cast<RVA>(string_file.SeekGet()); + + EXPECT_TRUE(string_file.Write(&build_id_cv, + offsetof(CodeViewRecordBuildID, build_id))); + EXPECT_TRUE(string_file.Write("atestbuildidbecausewhynot", 25)); + + auto build_id_cv_size = + static_cast<size_t>(string_file.SeekGet() - build_id_cv_loc); MINIDUMP_DIRECTORY minidump_module_list_directory = {}; minidump_module_list_directory.StreamType = kMinidumpStreamTypeModuleList; @@ -355,6 +367,15 @@ TEST(ProcessSnapshotMinidump, Modules) { for (uint32_t minidump_module_index = 0; minidump_module_index < minidump_module_count; ++minidump_module_index) { + if (minidump_module_index % 2) { + minidump_module.CvRecord.Rva = pdb70_loc; + minidump_module.CvRecord.DataSize = static_cast<uint32_t>(pdb70_size); + } else { + minidump_module.CvRecord.Rva = build_id_cv_loc; + minidump_module.CvRecord.DataSize = + static_cast<uint32_t>(build_id_cv_size); + } + minidump_module.ModuleNameRva = name_rvas[minidump_module_index]; EXPECT_TRUE(string_file.Write(&minidump_module, sizeof(minidump_module))); minidump_module.TimeDateStamp++; @@ -479,12 +500,19 @@ TEST(ProcessSnapshotMinidump, Modules) { EXPECT_EQ(modules[i]->GetModuleType(), ModuleSnapshot::kModuleTypeExecutable); - uint32_t age; - UUID uuid; - modules[i]->UUIDAndAge(&uuid, &age); + if (i % 2) { + uint32_t age; + UUID uuid; + modules[i]->UUIDAndAge(&uuid, &age); - EXPECT_EQ(uuid.ToString(), "00112233-4455-6677-8899-aabbccddeeff"); - EXPECT_EQ(age, 7U); + EXPECT_EQ(uuid.ToString(), "00112233-4455-6677-8899-aabbccddeeff"); + EXPECT_EQ(age, 7U); + } else { + auto build_id = modules[i]->BuildID(); + std::string build_id_text(build_id.data(), + build_id.data() + build_id.size()); + EXPECT_EQ(build_id_text, "atestbuildidbecausewhynot"); + } } auto annotations_simple_map = modules[0]->AnnotationsSimpleMap(); @@ -626,8 +654,8 @@ TEST(ProcessSnapshotMinidump, System) { minidump_system_info_directory.Location.Rva = static_cast<RVA>(string_file.SeekGet()); - ASSERT_TRUE(string_file.Write(&minidump_system_info, - sizeof(minidump_system_info))); + ASSERT_TRUE( + string_file.Write(&minidump_system_info, sizeof(minidump_system_info))); header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); ASSERT_TRUE(string_file.Write(&minidump_system_info_directory, @@ -680,8 +708,8 @@ TEST(ProcessSnapshotMinidump, ThreadContextARM64) { minidump_system_info_directory.Location.Rva = static_cast<RVA>(string_file.SeekGet()); - ASSERT_TRUE(string_file.Write(&minidump_system_info, - sizeof(minidump_system_info))); + ASSERT_TRUE( + string_file.Write(&minidump_system_info, sizeof(minidump_system_info))); MINIDUMP_THREAD minidump_thread = {}; uint32_t minidump_thread_count = 1; @@ -801,8 +829,8 @@ TEST(ProcessSnapshotMinidump, ThreadContextX86_64) { minidump_system_info_directory.Location.Rva = static_cast<RVA>(string_file.SeekGet()); - ASSERT_TRUE(string_file.Write(&minidump_system_info, - sizeof(minidump_system_info))); + ASSERT_TRUE( + string_file.Write(&minidump_system_info, sizeof(minidump_system_info))); MINIDUMP_THREAD minidump_thread = {}; uint32_t minidump_thread_count = 1; @@ -1015,7 +1043,7 @@ TEST(ProcessSnapshotMinidump, MemoryMap) { MINIDUMP_DIRECTORY minidump_memory_info_list_directory = {}; minidump_memory_info_list_directory.StreamType = - kMinidumpStreamTypeMemoryInfoList; + kMinidumpStreamTypeMemoryInfoList; minidump_memory_info_list_directory.Location.DataSize = sizeof(minidump_memory_info_list) + minidump_memory_info_count * sizeof(MINIDUMP_MEMORY_INFO); @@ -1043,12 +1071,16 @@ TEST(ProcessSnapshotMinidump, MemoryMap) { EXPECT_TRUE(process_snapshot.Initialize(&string_file)); std::vector<const MemoryMapRegionSnapshot*> map = - process_snapshot.MemoryMap(); + process_snapshot.MemoryMap(); ASSERT_EQ(map.size(), minidump_memory_info_count); - EXPECT_EQ(memcmp(&map[0]->AsMinidumpMemoryInfo(), &minidump_memory_info_1, - sizeof(minidump_memory_info_1)), 0); - EXPECT_EQ(memcmp(&map[1]->AsMinidumpMemoryInfo(), &minidump_memory_info_2, - sizeof(minidump_memory_info_2)), 0); + EXPECT_EQ(memcmp(&map[0]->AsMinidumpMemoryInfo(), + &minidump_memory_info_1, + sizeof(minidump_memory_info_1)), + 0); + EXPECT_EQ(memcmp(&map[1]->AsMinidumpMemoryInfo(), + &minidump_memory_info_2, + sizeof(minidump_memory_info_2)), + 0); } TEST(ProcessSnapshotMinidump, Stacks) { @@ -1063,9 +1095,21 @@ TEST(ProcessSnapshotMinidump, Stacks) { minidump_thread.ThreadId = 42; minidump_thread.Stack.StartOfMemoryRange = 0xbeefd00d; - std::vector<uint8_t> minidump_stack = { - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; + std::vector<uint8_t> minidump_stack = {'1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f'}; minidump_thread.Stack.Memory.DataSize = base::checked_cast<uint32_t>(minidump_stack.size()); diff --git a/snapshot/module_snapshot.h b/snapshot/module_snapshot.h index eea74660..f7eb83c8 100644 --- a/snapshot/module_snapshot.h +++ b/snapshot/module_snapshot.h @@ -146,6 +146,7 @@ class ModuleSnapshot { //! Windows with incremental linking. On other platforms \a age will always be //! `0`. //! + //! \sa BuildID() //! \sa DebugFileName() virtual void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const = 0; @@ -159,6 +160,20 @@ class ModuleSnapshot { //! \sa UUIDAndAge() virtual std::string DebugFileName() const = 0; + //! \brief Returns the module’s build ID. + //! + //! On ELF platforms, the build ID is a variable-length byte stream that + //! identifies a library uniquely, and is usually used to look up its debug + //! symbols when stored separately. This will return an empty vector if it is + //! unsupported. + //! + //! BuildID() and UUIDAndAge() are never available in the same place. When + //! UUIDAndAge() is unavailable, it will be filled out with the contents of + //! BuildID() (either 0-padded or truncated) and age will be zero. + //! + //! \sa UUIDAndAge() + virtual std::vector<uint8_t> BuildID() const = 0; + //! \brief Returns string annotations recorded in the module. //! //! This method retrieves annotations recorded in a module. These annotations diff --git a/snapshot/sanitized/module_snapshot_sanitized.cc b/snapshot/sanitized/module_snapshot_sanitized.cc index 94cb3d00..32b13578 100644 --- a/snapshot/sanitized/module_snapshot_sanitized.cc +++ b/snapshot/sanitized/module_snapshot_sanitized.cc @@ -81,6 +81,10 @@ std::string ModuleSnapshotSanitized::DebugFileName() const { return snapshot_->DebugFileName(); } +std::vector<uint8_t> ModuleSnapshotSanitized::BuildID() const { + return snapshot_->BuildID(); +} + std::vector<std::string> ModuleSnapshotSanitized::AnnotationsVector() const { // TODO(jperaza): If/when AnnotationsVector() begins to be used, determine // whether and how the content should be sanitized. diff --git a/snapshot/sanitized/module_snapshot_sanitized.h b/snapshot/sanitized/module_snapshot_sanitized.h index 4f375ce0..bbe1f5f4 100644 --- a/snapshot/sanitized/module_snapshot_sanitized.h +++ b/snapshot/sanitized/module_snapshot_sanitized.h @@ -56,6 +56,7 @@ class ModuleSnapshotSanitized final : public ModuleSnapshot { ModuleType GetModuleType() const override; void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override; std::string DebugFileName() const override; + std::vector<uint8_t> BuildID() const override; std::vector<std::string> AnnotationsVector() const override; std::map<std::string, std::string> AnnotationsSimpleMap() const override; std::vector<AnnotationSnapshot> AnnotationObjects() const override; diff --git a/snapshot/test/test_module_snapshot.cc b/snapshot/test/test_module_snapshot.cc index 9141edad..ad0c2dec 100644 --- a/snapshot/test/test_module_snapshot.cc +++ b/snapshot/test/test_module_snapshot.cc @@ -30,11 +30,9 @@ TestModuleSnapshot::TestModuleSnapshot() debug_file_name_(), annotations_vector_(), annotations_simple_map_(), - extra_memory_ranges_() { -} + extra_memory_ranges_() {} -TestModuleSnapshot::~TestModuleSnapshot() { -} +TestModuleSnapshot::~TestModuleSnapshot() {} std::string TestModuleSnapshot::Name() const { return name_; @@ -85,6 +83,10 @@ std::string TestModuleSnapshot::DebugFileName() const { return debug_file_name_; } +std::vector<uint8_t> TestModuleSnapshot::BuildID() const { + return build_id_; +} + std::vector<std::string> TestModuleSnapshot::AnnotationsVector() const { return annotations_vector_; } diff --git a/snapshot/test/test_module_snapshot.h b/snapshot/test/test_module_snapshot.h index d1262fa6..fb84aaf4 100644 --- a/snapshot/test/test_module_snapshot.h +++ b/snapshot/test/test_module_snapshot.h @@ -64,6 +64,9 @@ class TestModuleSnapshot final : public ModuleSnapshot { uuid_ = uuid; age_ = age; } + void SetBuildID(const std::vector<uint8_t>& build_id) { + build_id_ = build_id; + } void SetDebugFileName(const std::string& debug_file_name) { debug_file_name_ = debug_file_name; } @@ -101,6 +104,7 @@ class TestModuleSnapshot final : public ModuleSnapshot { ModuleType GetModuleType() const override; void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override; std::string DebugFileName() const override; + std::vector<uint8_t> BuildID() const override; std::vector<std::string> AnnotationsVector() const override; std::map<std::string, std::string> AnnotationsSimpleMap() const override; std::vector<AnnotationSnapshot> AnnotationObjects() const override; @@ -117,6 +121,7 @@ class TestModuleSnapshot final : public ModuleSnapshot { ModuleType module_type_; uint32_t age_; crashpad::UUID uuid_; + std::vector<uint8_t> build_id_; std::string debug_file_name_; std::vector<std::string> annotations_vector_; std::map<std::string, std::string> annotations_simple_map_; diff --git a/snapshot/win/module_snapshot_win.cc b/snapshot/win/module_snapshot_win.cc index d9d74c1b..49d178a8 100644 --- a/snapshot/win/module_snapshot_win.cc +++ b/snapshot/win/module_snapshot_win.cc @@ -44,8 +44,7 @@ ModuleSnapshotWin::ModuleSnapshotWin() age_(0), initialized_() {} -ModuleSnapshotWin::~ModuleSnapshotWin() { -} +ModuleSnapshotWin::~ModuleSnapshotWin() {} bool ModuleSnapshotWin::Initialize( ProcessReaderWin* process_reader, @@ -195,6 +194,11 @@ std::string ModuleSnapshotWin::DebugFileName() const { return pdb_name_; } +std::vector<uint8_t> ModuleSnapshotWin::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<uint8_t>(); +} + std::vector<std::string> ModuleSnapshotWin::AnnotationsVector() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); // These correspond to system-logged things on Mac. We don't currently track diff --git a/snapshot/win/module_snapshot_win.h b/snapshot/win/module_snapshot_win.h index f18a8809..b32216c3 100644 --- a/snapshot/win/module_snapshot_win.h +++ b/snapshot/win/module_snapshot_win.h @@ -84,6 +84,7 @@ class ModuleSnapshotWin final : public ModuleSnapshot { ModuleType GetModuleType() const override; void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override; std::string DebugFileName() const override; + std::vector<uint8_t> BuildID() const override; std::vector<std::string> AnnotationsVector() const override; std::map<std::string, std::string> AnnotationsSimpleMap() const override; std::vector<AnnotationSnapshot> AnnotationObjects() const override; diff --git a/util/misc/pdb_structures.cc b/util/misc/pdb_structures.cc index c62f11c0..e904dc63 100644 --- a/util/misc/pdb_structures.cc +++ b/util/misc/pdb_structures.cc @@ -18,5 +18,6 @@ namespace crashpad { const uint32_t CodeViewRecordPDB20::kSignature; const uint32_t CodeViewRecordPDB70::kSignature; +const uint32_t CodeViewRecordBuildID::kSignature; } // namespace crashpad diff --git a/util/misc/pdb_structures.h b/util/misc/pdb_structures.h index d0cc9a32..834cfdc8 100644 --- a/util/misc/pdb_structures.h +++ b/util/misc/pdb_structures.h @@ -90,12 +90,7 @@ struct CodeViewRecordPDB70 { // UUID has a constructor, which makes it non-POD, which makes this structure // non-POD. In order for the default constructor to zero-initialize other // members, an explicit constructor must be provided. - CodeViewRecordPDB70() - : signature(), - uuid(), - age(), - pdb_name() { - } + CodeViewRecordPDB70() : signature(), uuid(), age(), pdb_name() {} //! \brief The magic number identifying this structure version, stored in //! #signature. @@ -127,6 +122,27 @@ struct CodeViewRecordPDB70 { uint8_t pdb_name[1]; }; +//! \brief A CodeView record containing an ELF build-id. +//! +//! This identifier comes from the ELF section `NT_GNU_BUILD_ID`. +struct CodeViewRecordBuildID { + //! \brief The magic number identifying this structure version, stored in + //! #signature. + //! + //! In a hex dump, this will appear as “LEpB” when produced by a little-endian + //! machine. + static const uint32_t kSignature = 'BpEL'; + + //! \brief The magic number identifying this structure version, the value of + //! #kSignature. + uint32_t signature; + + //! \brief The build ID for this object. + //! + //! This usually comes from `NT_GNU_BUILD_ID` on ELF objects. + uint8_t build_id[1]; +}; + } // namespace crashpad #endif // CRASHPAD_UTIL_MISC_PDB_STRUCTURES_H_ From 93366d782aabdfbb4e94242cf13f7d5cb77a5098 Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Fri, 19 Apr 2019 11:23:28 -0700 Subject: [PATCH 184/401] Make OSVersionFull work for SystemSnapshotMinidump Bug: crashpad:10 Change-Id: I98c630d4c9c9ba4b5a4d7f9605102827bf185cc3 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1575663 Commit-Queue: Casey Dahlin <sadmac@google.com> Reviewed-by: Mark Mentovai <mark@chromium.org> --- .../minidump/process_snapshot_minidump.cc | 28 +++--- snapshot/minidump/process_snapshot_minidump.h | 1 + .../process_snapshot_minidump_test.cc | 22 ++++- snapshot/minidump/system_snapshot_minidump.cc | 89 +++++++++---------- snapshot/minidump/system_snapshot_minidump.h | 7 +- 5 files changed, 89 insertions(+), 58 deletions(-) diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index f191cb95..1242b49c 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -16,6 +16,7 @@ #include <utility> +#include "base/strings/utf_string_conversions.h" #include "minidump/minidump_extensions.h" #include "snapshot/memory_map_region_snapshot.h" #include "snapshot/minidump/minidump_simple_string_dictionary_reader.h" @@ -60,8 +61,7 @@ ProcessSnapshotMinidump::ProcessSnapshotMinidump() process_id_(static_cast<pid_t>(-1)), initialized_() {} -ProcessSnapshotMinidump::~ProcessSnapshotMinidump() { -} +ProcessSnapshotMinidump::~ProcessSnapshotMinidump() {} bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); @@ -310,6 +310,9 @@ bool ProcessSnapshotMinidump::InitializeMiscInfo() { switch (stream_it->second->DataSize) { case sizeof(MINIDUMP_MISC_INFO_5): case sizeof(MINIDUMP_MISC_INFO_4): + full_version_ = base::UTF16ToUTF8(info.BuildString); + full_version_ = full_version_.substr(0, full_version_.find(";")); + FALLTHROUGH; case sizeof(MINIDUMP_MISC_INFO_3): case sizeof(MINIDUMP_MISC_INFO_2): case sizeof(MINIDUMP_MISC_INFO): @@ -347,7 +350,7 @@ bool ProcessSnapshotMinidump::InitializeModules() { } if (sizeof(MINIDUMP_MODULE_LIST) + module_count * sizeof(MINIDUMP_MODULE) != - stream_it->second->DataSize) { + stream_it->second->DataSize) { LOG(ERROR) << "module_list size mismatch"; return false; } @@ -389,7 +392,7 @@ bool ProcessSnapshotMinidump::InitializeModulesCrashpadInfo( } if (crashpad_info_.module_list.DataSize < - sizeof(MinidumpModuleCrashpadInfoList)) { + sizeof(MinidumpModuleCrashpadInfoList)) { LOG(ERROR) << "module_crashpad_info_list size mismatch"; return false; } @@ -405,8 +408,8 @@ bool ProcessSnapshotMinidump::InitializeModulesCrashpadInfo( } if (crashpad_info_.module_list.DataSize != - sizeof(MinidumpModuleCrashpadInfoList) + - crashpad_module_count * sizeof(MinidumpModuleCrashpadInfoLink)) { + sizeof(MinidumpModuleCrashpadInfoList) + + crashpad_module_count * sizeof(MinidumpModuleCrashpadInfoLink)) { LOG(ERROR) << "module_crashpad_info_list size mismatch"; return false; } @@ -426,7 +429,8 @@ bool ProcessSnapshotMinidump::InitializeModulesCrashpadInfo( minidump_links[crashpad_module_index]; if (!module_crashpad_info_links ->insert(std::make_pair(minidump_link.minidump_module_list_index, - minidump_link.location)).second) { + minidump_link.location)) + .second) { LOG(WARNING) << "duplicate module_crashpad_info_list minidump_module_list_index " << minidump_link.minidump_module_list_index; @@ -467,7 +471,8 @@ bool ProcessSnapshotMinidump::InitializeMemoryInfo() { } if (sizeof(MINIDUMP_MEMORY_INFO_LIST) + - list.NumberOfEntries * list.SizeOfEntry != stream_it->second->DataSize) { + list.NumberOfEntries * list.SizeOfEntry != + stream_it->second->DataSize) { LOG(ERROR) << "memory_info_list size mismatch"; return false; } @@ -480,7 +485,7 @@ bool ProcessSnapshotMinidump::InitializeMemoryInfo() { } mem_regions_.emplace_back( - std::make_unique<internal::MemoryMapRegionSnapshotMinidump>(info)); + std::make_unique<internal::MemoryMapRegionSnapshotMinidump>(info)); mem_regions_exposed_.emplace_back(mem_regions_.back().get()); } @@ -508,7 +513,7 @@ bool ProcessSnapshotMinidump::InitializeThreads() { } if (sizeof(MINIDUMP_THREAD_LIST) + thread_count * sizeof(MINIDUMP_THREAD) != - stream_it->second->DataSize) { + stream_it->second->DataSize) { LOG(ERROR) << "thread_list size mismatch"; return false; } @@ -539,7 +544,8 @@ bool ProcessSnapshotMinidump::InitializeSystemSnapshot() { return false; } - if (!system_snapshot_.Initialize(file_reader_, stream_it->second->Rva)) { + if (!system_snapshot_.Initialize( + file_reader_, stream_it->second->Rva, full_version_)) { return false; } diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 2df59d29..5713aad8 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -149,6 +149,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { internal::ExceptionSnapshotMinidump exception_snapshot_; CPUArchitecture arch_; std::map<std::string, std::string> annotations_simple_map_; + std::string full_version_; FileReaderInterface* file_reader_; // weak pid_t process_id_; InitializationStateDcheck initialized_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 7d5d16d3..a471fbca 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -18,6 +18,7 @@ #include <dbghelp.h> #include <string.h> +#include <algorithm> #include <memory> #include "base/numerics/safe_math.h" @@ -647,6 +648,13 @@ TEST(ProcessSnapshotMinidump, System) { minidump_system_info.Cpu.X86CpuInfo.VendorId[1] = cpu_info_bytes[1]; minidump_system_info.Cpu.X86CpuInfo.VendorId[2] = cpu_info_bytes[2]; + MINIDUMP_MISC_INFO_5 minidump_misc_info = {}; + base::string16 build_string; + ASSERT_TRUE(base::UTF8ToUTF16( + "MyOSVersion; MyMachineDescription", 33, &build_string)); + std::copy(build_string.begin(), build_string.end(), + minidump_misc_info.BuildString); + MINIDUMP_DIRECTORY minidump_system_info_directory = {}; minidump_system_info_directory.StreamType = kMinidumpStreamTypeSystemInfo; minidump_system_info_directory.Location.DataSize = @@ -657,13 +665,24 @@ TEST(ProcessSnapshotMinidump, System) { ASSERT_TRUE( string_file.Write(&minidump_system_info, sizeof(minidump_system_info))); + MINIDUMP_DIRECTORY minidump_misc_info_directory = {}; + minidump_misc_info_directory.StreamType = kMinidumpStreamTypeMiscInfo; + minidump_misc_info_directory.Location.DataSize = sizeof(MINIDUMP_MISC_INFO_5); + minidump_misc_info_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + ASSERT_TRUE( + string_file.Write(&minidump_misc_info, sizeof(minidump_misc_info))); + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); ASSERT_TRUE(string_file.Write(&minidump_system_info_directory, sizeof(minidump_system_info_directory))); + ASSERT_TRUE(string_file.Write(&minidump_misc_info_directory, + sizeof(minidump_misc_info_directory))); header.Signature = MINIDUMP_SIGNATURE; header.Version = MINIDUMP_VERSION; - header.NumberOfStreams = 1; + header.NumberOfStreams = 2; EXPECT_TRUE(string_file.SeekSet(0)); EXPECT_TRUE(string_file.Write(&header, sizeof(header))); @@ -677,6 +696,7 @@ TEST(ProcessSnapshotMinidump, System) { EXPECT_EQ(s->CPUVendor(), "GenuineIntel"); EXPECT_EQ(s->GetOperatingSystem(), SystemSnapshot::OperatingSystem::kOperatingSystemFuchsia); + EXPECT_EQ(s->OSVersionFull(), "MyOSVersion"); int major, minor, bugfix; std::string build; diff --git a/snapshot/minidump/system_snapshot_minidump.cc b/snapshot/minidump/system_snapshot_minidump.cc index 356bd16c..06bae484 100644 --- a/snapshot/minidump/system_snapshot_minidump.cc +++ b/snapshot/minidump/system_snapshot_minidump.cc @@ -20,17 +20,17 @@ namespace crashpad { namespace internal { SystemSnapshotMinidump::SystemSnapshotMinidump() - : SystemSnapshot(), - minidump_system_info_(), - initialized_() { -} + : SystemSnapshot(), minidump_system_info_(), initialized_() {} -SystemSnapshotMinidump::~SystemSnapshotMinidump() { -} +SystemSnapshotMinidump::~SystemSnapshotMinidump() {} bool SystemSnapshotMinidump::Initialize(FileReaderInterface* file_reader, - RVA minidump_system_info_rva) { + RVA minidump_system_info_rva, + const std::string& version) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + full_version_ = version; + if (!file_reader->SeekSet(minidump_system_info_rva)) { return false; } @@ -40,7 +40,8 @@ bool SystemSnapshotMinidump::Initialize(FileReaderInterface* file_reader, return false; } - if (!ReadMinidumpUTF8String(file_reader, minidump_system_info_.CSDVersionRva, + if (!ReadMinidumpUTF8String(file_reader, + minidump_system_info_.CSDVersionRva, &minidump_build_name_)) { return false; } @@ -52,23 +53,23 @@ bool SystemSnapshotMinidump::Initialize(FileReaderInterface* file_reader, CPUArchitecture SystemSnapshotMinidump::GetCPUArchitecture() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); switch (minidump_system_info_.ProcessorArchitecture) { - case kMinidumpCPUArchitectureAMD64: - return kCPUArchitectureX86_64; - case kMinidumpCPUArchitectureX86: - case kMinidumpCPUArchitectureX86Win64: - return kCPUArchitectureX86; - case kMinidumpCPUArchitectureARM: - case kMinidumpCPUArchitectureARM32Win64: - return kCPUArchitectureARM; - case kMinidumpCPUArchitectureARM64: - case kMinidumpCPUArchitectureARM64Breakpad: - return kCPUArchitectureARM64; - case kMinidumpCPUArchitectureMIPS: - return kCPUArchitectureMIPSEL; - // No word on how MIPS64 is signalled + case kMinidumpCPUArchitectureAMD64: + return kCPUArchitectureX86_64; + case kMinidumpCPUArchitectureX86: + case kMinidumpCPUArchitectureX86Win64: + return kCPUArchitectureX86; + case kMinidumpCPUArchitectureARM: + case kMinidumpCPUArchitectureARM32Win64: + return kCPUArchitectureARM; + case kMinidumpCPUArchitectureARM64: + case kMinidumpCPUArchitectureARM64Breakpad: + return kCPUArchitectureARM64; + case kMinidumpCPUArchitectureMIPS: + return kCPUArchitectureMIPSEL; + // No word on how MIPS64 is signalled - default: - return CPUArchitecture::kCPUArchitectureUnknown; + default: + return CPUArchitecture::kCPUArchitectureUnknown; } } @@ -85,9 +86,8 @@ uint8_t SystemSnapshotMinidump::CPUCount() const { std::string SystemSnapshotMinidump::CPUVendor() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); if (GetCPUArchitecture() == kCPUArchitectureX86) { - const char* ptr = - reinterpret_cast<const char*>(minidump_system_info_.Cpu.X86CpuInfo. - VendorId); + const char* ptr = reinterpret_cast<const char*>( + minidump_system_info_.Cpu.X86CpuInfo.VendorId); return std::string(ptr, ptr + (3 * sizeof(uint32_t))); } else { return std::string(); @@ -130,25 +130,25 @@ bool SystemSnapshotMinidump::CPUX86SupportsDAZ() const { return false; } -SystemSnapshot::OperatingSystem - SystemSnapshotMinidump::GetOperatingSystem() const { +SystemSnapshot::OperatingSystem SystemSnapshotMinidump::GetOperatingSystem() + const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); switch (minidump_system_info_.PlatformId) { - case kMinidumpOSMacOSX: - return OperatingSystem::kOperatingSystemMacOSX; - case kMinidumpOSWin32s: - case kMinidumpOSWin32Windows: - case kMinidumpOSWin32NT: - return OperatingSystem::kOperatingSystemWindows; - case kMinidumpOSLinux: - return OperatingSystem::kOperatingSystemLinux; - case kMinidumpOSAndroid: - return OperatingSystem::kOperatingSystemAndroid; - case kMinidumpOSFuchsia: - return OperatingSystem::kOperatingSystemFuchsia; - default: - return OperatingSystem::kOperatingSystemUnknown; + case kMinidumpOSMacOSX: + return OperatingSystem::kOperatingSystemMacOSX; + case kMinidumpOSWin32s: + case kMinidumpOSWin32Windows: + case kMinidumpOSWin32NT: + return OperatingSystem::kOperatingSystemWindows; + case kMinidumpOSLinux: + return OperatingSystem::kOperatingSystemLinux; + case kMinidumpOSAndroid: + return OperatingSystem::kOperatingSystemAndroid; + case kMinidumpOSFuchsia: + return OperatingSystem::kOperatingSystemFuchsia; + default: + return OperatingSystem::kOperatingSystemUnknown; } } @@ -170,8 +170,7 @@ void SystemSnapshotMinidump::OSVersion(int* major, std::string SystemSnapshotMinidump::OSVersionFull() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return std::string(); + return full_version_; } std::string SystemSnapshotMinidump::MachineDescription() const { diff --git a/snapshot/minidump/system_snapshot_minidump.h b/snapshot/minidump/system_snapshot_minidump.h index 71e57891..0f2880e1 100644 --- a/snapshot/minidump/system_snapshot_minidump.h +++ b/snapshot/minidump/system_snapshot_minidump.h @@ -38,11 +38,14 @@ class SystemSnapshotMinidump : public SystemSnapshot { //! The file reader must support seeking. //! \param[in] minidump_system_info_rva The file offset in \a file_reader at //! which the thread’s MINIDUMP_SYSTEM_INFO structure is located. + //! \param[in] version The OS version taken from the build string in + //! MINIDUMP_MISC_INFO_4. //! //! \return `true` if the snapshot could be created, `false` otherwise with //! an appropriate message logged. bool Initialize(FileReaderInterface* file_reader, - RVA minidump_system_info_rva); + RVA minidump_system_info_rva, + const std::string& version); CPUArchitecture GetCPUArchitecture() const override; uint32_t CPURevision() const override; @@ -68,9 +71,11 @@ class SystemSnapshotMinidump : public SystemSnapshot { int* daylight_offset_seconds, std::string* standard_name, std::string* daylight_name) const override; + private: MINIDUMP_SYSTEM_INFO minidump_system_info_; std::string minidump_build_name_; + std::string full_version_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(SystemSnapshotMinidump); From c96226c6baa853f43981b0240974e33a0b661f8d Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 23 Apr 2019 09:59:29 -0700 Subject: [PATCH 185/401] linux: move handler protocol types into a class This patch adds the class ExceptionHandlerProtocol to contain all the relevant types, but should not make any functional changes. Change-Id: I65ada239a6bf3195899fdd96f005c042cdd59749 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1575796 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_linux_test.cc | 2 +- handler/handler_main.cc | 2 +- .../linux/crash_report_exception_handler.cc | 6 +- .../linux/crash_report_exception_handler.h | 22 ++-- handler/linux/exception_handler_server.cc | 44 ++++--- handler/linux/exception_handler_server.h | 29 +++-- .../linux/exception_handler_server_test.cc | 22 ++-- util/linux/exception_handler_client.cc | 29 +++-- util/linux/exception_handler_client.h | 7 +- util/linux/exception_handler_protocol.cc | 4 +- util/linux/exception_handler_protocol.h | 119 ++++++++++-------- util/linux/ptrace_broker.cc | 25 ++-- util/linux/ptrace_broker.h | 4 +- util/linux/ptrace_client.cc | 12 +- 14 files changed, 181 insertions(+), 146 deletions(-) diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index f61ea44f..68a49e7c 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -342,7 +342,7 @@ class StartHandlerForClientTest { context); exception_information.thread_id = syscall(SYS_gettid); - ClientInformation info; + ExceptionHandlerProtocol::ClientInformation info; info.exception_information_address = FromPointerCast<decltype(info.exception_information_address)>( &exception_information); diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 31686b3e..e87d17b7 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -880,7 +880,7 @@ int HandlerMain(int argc, #if defined(OS_LINUX) || defined(OS_ANDROID) if (options.exception_information_address) { - ClientInformation info; + ExceptionHandlerProtocol::ClientInformation info; info.exception_information_address = options.exception_information_address; info.sanitization_information_address = options.sanitization_information_address; diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 5401bafa..345e234d 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -45,7 +45,7 @@ CrashReportExceptionHandler::~CrashReportExceptionHandler() = default; bool CrashReportExceptionHandler::HandleException( pid_t client_process_id, - const ClientInformation& info, + const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, UUID* local_report_id) { @@ -67,7 +67,7 @@ bool CrashReportExceptionHandler::HandleException( bool CrashReportExceptionHandler::HandleExceptionWithBroker( pid_t client_process_id, - const ClientInformation& info, + const ExceptionHandlerProtocol::ClientInformation& info, int broker_sock, UUID* local_report_id) { Metrics::ExceptionEncountered(); @@ -85,7 +85,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithBroker( bool CrashReportExceptionHandler::HandleExceptionWithConnection( PtraceConnection* connection, - const ClientInformation& info, + const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, UUID* local_report_id) { diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index 18051656..dba8b63a 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -65,22 +65,24 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { // ExceptionHandlerServer::Delegate: bool HandleException(pid_t client_process_id, - const ClientInformation& info, + const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address = 0, pid_t* requesting_thread_id = nullptr, UUID* local_report_id = nullptr) override; - bool HandleExceptionWithBroker(pid_t client_process_id, - const ClientInformation& info, - int broker_sock, - UUID* local_report_id = nullptr) override; + bool HandleExceptionWithBroker( + pid_t client_process_id, + const ExceptionHandlerProtocol::ClientInformation& info, + int broker_sock, + UUID* local_report_id = nullptr) override; private: - bool HandleExceptionWithConnection(PtraceConnection* connection, - const ClientInformation& info, - VMAddress requesting_thread_stack_address, - pid_t* requesting_thread_id, - UUID* local_report_id = nullptr); + bool HandleExceptionWithConnection( + PtraceConnection* connection, + const ExceptionHandlerProtocol::ClientInformation& info, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id, + UUID* local_report_id = nullptr); CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index c2842120..4cefd8b4 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -110,10 +110,13 @@ bool HaveCapSysPtrace() { return (cap_data.effective & (1 << CAP_SYS_PTRACE)) != 0; } -bool SendMessageToClient(int client_sock, ServerToClientMessage::Type type) { - ServerToClientMessage message = {}; +bool SendMessageToClient( + int client_sock, + ExceptionHandlerProtocol::ServerToClientMessage::Type type) { + ExceptionHandlerProtocol::ServerToClientMessage message = {}; message.type = type; - if (type == ServerToClientMessage::kTypeSetPtracer) { + if (type == + ExceptionHandlerProtocol::ServerToClientMessage::kTypeSetPtracer) { message.pid = getpid(); } return LoggingWriteFile(client_sock, &message, sizeof(message)); @@ -134,11 +137,12 @@ class PtraceStrategyDeciderImpl : public PtraceStrategyDecider { case PtraceScope::kRestricted: if (!SendMessageToClient(sock, - ServerToClientMessage::kTypeSetPtracer)) { + ExceptionHandlerProtocol:: + ServerToClientMessage::kTypeSetPtracer)) { return Strategy::kError; } - Errno status; + ExceptionHandlerProtocol::Errno status; if (!LoggingReadFileExactly(sock, &status, sizeof(status))) { return Strategy::kError; } @@ -170,12 +174,13 @@ class PtraceStrategyDeciderImpl : public PtraceStrategyDecider { private: static Strategy TryForkingBroker(int client_sock) { - if (!SendMessageToClient(client_sock, - ServerToClientMessage::kTypeForkBroker)) { + if (!SendMessageToClient( + client_sock, + ExceptionHandlerProtocol::ServerToClientMessage::kTypeForkBroker)) { return Strategy::kError; } - Errno status; + ExceptionHandlerProtocol::Errno status; if (!LoggingReadFileExactly(client_sock, &status, sizeof(status))) { return Strategy::kError; } @@ -369,7 +374,7 @@ bool ExceptionHandlerServer::UninstallClientSocket(Event* event) { } bool ExceptionHandlerServer::ReceiveClientMessage(Event* event) { - ClientToServerMessage message; + ExceptionHandlerProtocol::ClientToServerMessage message; iovec iov; iov.iov_base = &message; iov.iov_len = sizeof(message); @@ -405,15 +410,17 @@ bool ExceptionHandlerServer::ReceiveClientMessage(Event* event) { return false; } - if (msg.msg_iov[0].iov_len != sizeof(ClientToServerMessage)) { + if (msg.msg_iov[0].iov_len != + sizeof(ExceptionHandlerProtocol::ClientToServerMessage)) { LOG(ERROR) << "unexpected message size " << msg.msg_iov[0].iov_len; return false; } auto client_msg = - reinterpret_cast<ClientToServerMessage*>(msg.msg_iov[0].iov_base); + reinterpret_cast<ExceptionHandlerProtocol::ClientToServerMessage*>( + msg.msg_iov[0].iov_base); switch (client_msg->type) { - case ClientToServerMessage::kCrashDumpRequest: + case ExceptionHandlerProtocol::ClientToServerMessage::kCrashDumpRequest: return HandleCrashDumpRequest(msg, client_msg->client_info, client_msg->requesting_thread_stack_address, @@ -427,7 +434,7 @@ bool ExceptionHandlerServer::ReceiveClientMessage(Event* event) { bool ExceptionHandlerServer::HandleCrashDumpRequest( const msghdr& msg, - const ClientInformation& client_info, + const ExceptionHandlerProtocol::ClientInformation& client_info, VMAddress requesting_thread_stack_address, int client_sock) { cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); @@ -459,8 +466,10 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( return false; case PtraceStrategyDecider::Strategy::kNoPtrace: - return SendMessageToClient(client_sock, - ServerToClientMessage::kTypeCrashDumpFailed); + return SendMessageToClient( + client_sock, + ExceptionHandlerProtocol::ServerToClientMessage:: + kTypeCrashDumpFailed); case PtraceStrategyDecider::Strategy::kDirectPtrace: delegate_->HandleException( @@ -473,8 +482,9 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( break; } - return SendMessageToClient(client_sock, - ServerToClientMessage::kTypeCrashDumpComplete); + return SendMessageToClient( + client_sock, + ExceptionHandlerProtocol::ServerToClientMessage::kTypeCrashDumpComplete); } } // namespace crashpad diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index 6f13fdc7..1b73601c 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -82,11 +82,12 @@ class ExceptionHandlerServer { //! \param[out] local_report_id The unique identifier for the report created //! in the local report database. Optional. //! \return `true` on success. `false` on failure with a message logged. - virtual bool HandleException(pid_t client_process_id, - const ClientInformation& info, - VMAddress requesting_thread_stack_address = 0, - pid_t* requesting_thread_id = nullptr, - UUID* local_report_id = nullptr) = 0; + virtual bool HandleException( + pid_t client_process_id, + const ExceptionHandlerProtocol::ClientInformation& info, + VMAddress requesting_thread_stack_address = 0, + pid_t* requesting_thread_id = nullptr, + UUID* local_report_id = nullptr) = 0; //! \brief Called on the receipt of a crash dump request from a client for a //! crash that should be mediated by a PtraceBroker. @@ -97,10 +98,11 @@ class ExceptionHandlerServer { //! \param[out] local_report_id The unique identifier for the report created //! in the local report database. Optional. //! \return `true` on success. `false` on failure with a message logged. - virtual bool HandleExceptionWithBroker(pid_t client_process_id, - const ClientInformation& info, - int broker_sock, - UUID* local_report_id = nullptr) = 0; + virtual bool HandleExceptionWithBroker( + pid_t client_process_id, + const ExceptionHandlerProtocol::ClientInformation& info, + int broker_sock, + UUID* local_report_id = nullptr) = 0; protected: ~Delegate() {} @@ -147,10 +149,11 @@ class ExceptionHandlerServer { bool InstallClientSocket(ScopedFileHandle socket); bool UninstallClientSocket(Event* event); bool ReceiveClientMessage(Event* event); - bool HandleCrashDumpRequest(const msghdr& msg, - const ClientInformation& client_info, - VMAddress requesting_thread_stack_address, - int client_sock); + bool HandleCrashDumpRequest( + const msghdr& msg, + const ExceptionHandlerProtocol::ClientInformation& client_info, + VMAddress requesting_thread_stack_address, + int client_sock); std::unordered_map<int, std::unique_ptr<Event>> clients_; std::unique_ptr<Event> shutdown_event_; diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index 7d15cbb9..1c57fce1 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -103,7 +103,7 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { } bool HandleException(pid_t client_process_id, - const ClientInformation& info, + const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id = nullptr, UUID* local_report_id = nullptr) override { @@ -134,10 +134,11 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { return true; } - bool HandleExceptionWithBroker(pid_t client_process_id, - const ClientInformation& info, - int broker_sock, - UUID* local_report_id = nullptr) override { + bool HandleExceptionWithBroker( + pid_t client_process_id, + const ExceptionHandlerProtocol::ClientInformation& info, + int broker_sock, + UUID* local_report_id = nullptr) override { PtraceClient client; bool connected = client.Initialize(broker_sock, client_process_id); EXPECT_TRUE(connected); @@ -165,10 +166,11 @@ class MockPtraceStrategyDecider : public PtraceStrategyDecider { Strategy ChooseStrategy(int sock, const ucred& client_credentials) override { if (strategy_ == Strategy::kUseBroker) { - ServerToClientMessage message = {}; - message.type = ServerToClientMessage::kTypeForkBroker; + ExceptionHandlerProtocol::ServerToClientMessage message = {}; + message.type = + ExceptionHandlerProtocol::ServerToClientMessage::kTypeForkBroker; - Errno status; + ExceptionHandlerProtocol::Errno status; bool result = LoggingWriteFile(sock, &message, sizeof(message)) && LoggingReadFileExactly(sock, &status, sizeof(status)); EXPECT_TRUE(result); @@ -220,7 +222,7 @@ class ExceptionHandlerServerTest : public testing::Test { ~CrashDumpTest() = default; void MultiprocessParent() override { - ClientInformation info; + ExceptionHandlerProtocol::ClientInformation info; ASSERT_TRUE( LoggingReadFileExactly(ReadPipeHandle(), &info, sizeof(info))); @@ -239,7 +241,7 @@ class ExceptionHandlerServerTest : public testing::Test { void MultiprocessChild() override { ASSERT_EQ(close(server_test_->sock_to_client_), 0); - ClientInformation info; + ExceptionHandlerProtocol::ClientInformation info; info.exception_information_address = 42; ASSERT_TRUE(LoggingWriteFile(WritePipeHandle(), &info, sizeof(info))); diff --git a/util/linux/exception_handler_client.cc b/util/linux/exception_handler_client.cc index e4548d62..60970695 100644 --- a/util/linux/exception_handler_client.cc +++ b/util/linux/exception_handler_client.cc @@ -35,7 +35,8 @@ ExceptionHandlerClient::ExceptionHandlerClient(int sock) ExceptionHandlerClient::~ExceptionHandlerClient() = default; -int ExceptionHandlerClient::RequestCrashDump(const ClientInformation& info) { +int ExceptionHandlerClient::RequestCrashDump( + const ExceptionHandlerProtocol::ClientInformation& info) { VMAddress sp = FromPointerCast<VMAddress>(&sp); int status = SendCrashDumpRequest(info, sp); @@ -64,10 +65,12 @@ void ExceptionHandlerClient::SetCanSetPtracer(bool can_set_ptracer) { can_set_ptracer_ = can_set_ptracer; } -int ExceptionHandlerClient::SendCrashDumpRequest(const ClientInformation& info, - VMAddress stack_pointer) { - ClientToServerMessage message; - message.type = ClientToServerMessage::kCrashDumpRequest; +int ExceptionHandlerClient::SendCrashDumpRequest( + const ExceptionHandlerProtocol::ClientInformation& info, + VMAddress stack_pointer) { + ExceptionHandlerProtocol::ClientToServerMessage message; + message.type = + ExceptionHandlerProtocol::ClientToServerMessage::kCrashDumpRequest; message.requesting_thread_stack_address = stack_pointer; message.client_info = info; @@ -105,19 +108,19 @@ int ExceptionHandlerClient::SendCrashDumpRequest(const ClientInformation& info, } int ExceptionHandlerClient::WaitForCrashDumpComplete() { - ServerToClientMessage message; + ExceptionHandlerProtocol::ServerToClientMessage message; // If the server hangs up, ReadFileExactly will return false without setting // errno. errno = 0; while (ReadFileExactly(server_sock_, &message, sizeof(message))) { switch (message.type) { - case ServerToClientMessage::kTypeForkBroker: { + case ExceptionHandlerProtocol::ServerToClientMessage::kTypeForkBroker: { Signals::InstallDefaultHandler(SIGCHLD); pid_t pid = fork(); if (pid <= 0) { - Errno error = pid < 0 ? errno : 0; + ExceptionHandlerProtocol::Errno error = pid < 0 ? errno : 0; if (!WriteFile(server_sock_, &error, sizeof(error))) { return errno; } @@ -148,16 +151,18 @@ int ExceptionHandlerClient::WaitForCrashDumpComplete() { continue; } - case ServerToClientMessage::kTypeSetPtracer: { - Errno result = SetPtracer(message.pid); + case ExceptionHandlerProtocol::ServerToClientMessage::kTypeSetPtracer: { + ExceptionHandlerProtocol::Errno result = SetPtracer(message.pid); if (!WriteFile(server_sock_, &result, sizeof(result))) { return errno; } continue; } - case ServerToClientMessage::kTypeCrashDumpComplete: - case ServerToClientMessage::kTypeCrashDumpFailed: + case ExceptionHandlerProtocol::ServerToClientMessage:: + kTypeCrashDumpComplete: + case ExceptionHandlerProtocol::ServerToClientMessage:: + kTypeCrashDumpFailed: return 0; } diff --git a/util/linux/exception_handler_client.h b/util/linux/exception_handler_client.h index 25a8a442..6492a12e 100644 --- a/util/linux/exception_handler_client.h +++ b/util/linux/exception_handler_client.h @@ -38,7 +38,7 @@ class ExceptionHandlerClient { //! //! \param[in] info Information about this client. //! \return 0 on success or an error code on failure. - int RequestCrashDump(const ClientInformation& info); + int RequestCrashDump(const ExceptionHandlerProtocol::ClientInformation& info); //! \brief Uses `prctl(PR_SET_PTRACER, ...)` to set the process with //! process ID \a pid as the ptracer for this process. @@ -53,8 +53,9 @@ class ExceptionHandlerClient { void SetCanSetPtracer(bool can_set_ptracer); private: - int SendCrashDumpRequest(const ClientInformation& info, - VMAddress stack_pointer); + int SendCrashDumpRequest( + const ExceptionHandlerProtocol::ClientInformation& info, + VMAddress stack_pointer); int WaitForCrashDumpComplete(); int server_sock_; diff --git a/util/linux/exception_handler_protocol.cc b/util/linux/exception_handler_protocol.cc index 3feca698..7ab77d39 100644 --- a/util/linux/exception_handler_protocol.cc +++ b/util/linux/exception_handler_protocol.cc @@ -16,10 +16,10 @@ namespace crashpad { -ClientInformation::ClientInformation() +ExceptionHandlerProtocol::ClientInformation::ClientInformation() : exception_information_address(0), sanitization_information_address(0) {} -ClientToServerMessage::ClientToServerMessage() +ExceptionHandlerProtocol::ClientToServerMessage::ClientToServerMessage() : version(kVersion), type(kCrashDumpRequest), client_info() {} } // namespace crashpad diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index 0ab3ffd0..d5eb5e88 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -19,81 +19,90 @@ #include <stdint.h> #include <sys/types.h> +#include "base/macros.h" #include "util/file/file_io.h" #include "util/misc/address_types.h" namespace crashpad { +class ExceptionHandlerProtocol { + public: #pragma pack(push, 1) -//! \brief The type used for error reporting. -using Errno = int32_t; -static_assert(sizeof(Errno) >= sizeof(errno), "Errno type is too small"); + //! \brief The type used for error reporting. + using Errno = int32_t; + static_assert(sizeof(Errno) >= sizeof(errno), "Errno type is too small"); -//! \brief A boolean status suitable for communication between processes. -enum Bool : char { kBoolFalse, kBoolTrue }; + //! \brief A boolean status suitable for communication between processes. + enum Bool : char { kBoolFalse, kBoolTrue }; -//! \brief Information about a client registered with an ExceptionHandlerServer. -struct ClientInformation { - //! \brief Constructs this object. - ClientInformation(); + //! \brief Information about a client registered with an + //! ExceptionHandlerServer. + struct ClientInformation { + //! \brief Constructs this object. + ClientInformation(); - //! \brief The address in the client's address space of an - //! ExceptionInformation struct. - VMAddress exception_information_address; + //! \brief The address in the client's address space of an + //! ExceptionInformation struct. + VMAddress exception_information_address; - //! \brief The address in the client's address space of a - //! SanitizationInformation struct, or 0 if there is no such struct. - VMAddress sanitization_information_address; -}; - -//! \brief The message passed from client to server. -struct ClientToServerMessage { - static constexpr int32_t kVersion = 1; - - //! \brief Constructs this object. - ClientToServerMessage(); - - //! \brief Indicates what message version is being used. - int32_t version; - - //! \brief A stack address of the thread sending the message. - VMAddress requesting_thread_stack_address; - - enum Type : uint32_t { - //! \brief Used to request a crash dump for the sending client. - kCrashDumpRequest - } type; - - union { - //! \brief Valid for type == kCrashDumpRequest - ClientInformation client_info; + //! \brief The address in the client's address space of a + //! SanitizationInformation struct, or 0 if there is no such struct. + VMAddress sanitization_information_address; }; -}; -//! \brief The message passed from server to client. -struct ServerToClientMessage { - enum Type : uint32_t { - //! \brief Indicates that the client should fork a PtraceBroker process. - kTypeForkBroker, + //! \brief The message passed from client to server. + struct ClientToServerMessage { + static constexpr int32_t kVersion = 1; - //! \brief Inidicates that the client should set allow the handler to trace - //! it using PR_SET_PTRACER. - kTypeSetPtracer, + //! \brief Constructs this object. + ClientToServerMessage(); - //! \brief Indicates that the handler has completed a requested crash dump. - kTypeCrashDumpComplete, + //! \brief Indicates what message version is being used. + int32_t version; - //! \brief Indicicates that the handler was unable to produce a crash dump. - kTypeCrashDumpFailed - } type; + //! \brief A stack address of the thread sending the message. + VMAddress requesting_thread_stack_address; - //! \brief The handler's process ID. Valid for kTypeSetPtracer. - pid_t pid; -}; + enum Type : uint32_t { + //! \brief Used to request a crash dump for the sending client. + kCrashDumpRequest + } type; + + union { + //! \brief Valid for type == kCrashDumpRequest + ClientInformation client_info; + }; + }; + + //! \brief The message passed from server to client. + struct ServerToClientMessage { + enum Type : uint32_t { + //! \brief Indicates that the client should fork a PtraceBroker process. + kTypeForkBroker, + + //! \brief Inidicates that the client should set allow the handler to + //! trace it using PR_SET_PTRACER. + kTypeSetPtracer, + + //! \brief Indicates that the handler has completed a requested crash + //! dump. + kTypeCrashDumpComplete, + + //! \brief Indicicates that the handler was unable to produce a crash + //! dump. + kTypeCrashDumpFailed + } type; + + //! \brief The handler's process ID. Valid for kTypeSetPtracer. + pid_t pid; + }; #pragma pack(pop) + DISALLOW_IMPLICIT_CONSTRUCTORS(ExceptionHandlerProtocol); +}; + } // namespace crashpad #endif // CRASHPAD_UTIL_LINUX_EXCEPTION_HANDLER_PROTOCOL_H_ diff --git a/util/linux/ptrace_broker.cc b/util/linux/ptrace_broker.cc index 4d7e4ced..6ec0af5b 100644 --- a/util/linux/ptrace_broker.cc +++ b/util/linux/ptrace_broker.cc @@ -139,9 +139,10 @@ int PtraceBroker::RunImpl() { attach_on_stack = true; } - Bool status = kBoolFalse; + ExceptionHandlerProtocol::Bool status = + ExceptionHandlerProtocol::kBoolFalse; if (attach->ResetAttach(request.tid)) { - status = kBoolTrue; + status = ExceptionHandlerProtocol::kBoolTrue; if (!attach_on_stack) { ++attach_count_; } @@ -151,21 +152,23 @@ int PtraceBroker::RunImpl() { return errno; } - if (status == kBoolFalse) { - Errno error = errno; + if (status == ExceptionHandlerProtocol::kBoolFalse) { + ExceptionHandlerProtocol::Errno error = errno; if (!WriteFile(sock_, &error, sizeof(error))) { return errno; } } - if (attach_on_stack && status == kBoolTrue) { + if (attach_on_stack && status == ExceptionHandlerProtocol::kBoolTrue) { return RunImpl(); } continue; } case Request::kTypeIs64Bit: { - Bool is_64_bit = ptracer_.Is64Bit() ? kBoolTrue : kBoolFalse; + ExceptionHandlerProtocol::Bool is_64_bit = + ptracer_.Is64Bit() ? ExceptionHandlerProtocol::kBoolTrue + : ExceptionHandlerProtocol::kBoolFalse; if (!WriteFile(sock_, &is_64_bit, sizeof(is_64_bit))) { return errno; } @@ -175,15 +178,15 @@ int PtraceBroker::RunImpl() { case Request::kTypeGetThreadInfo: { GetThreadInfoResponse response; response.success = ptracer_.GetThreadInfo(request.tid, &response.info) - ? kBoolTrue - : kBoolFalse; + ? ExceptionHandlerProtocol::kBoolTrue + : ExceptionHandlerProtocol::kBoolFalse; if (!WriteFile(sock_, &response, sizeof(response))) { return errno; } - if (response.success == kBoolFalse) { - Errno error = errno; + if (response.success == ExceptionHandlerProtocol::kBoolFalse) { + ExceptionHandlerProtocol::Errno error = errno; if (!WriteFile(sock_, &error, sizeof(error))) { return errno; } @@ -249,7 +252,7 @@ int PtraceBroker::RunImpl() { } } -int PtraceBroker::SendError(Errno err) { +int PtraceBroker::SendError(ExceptionHandlerProtocol::Errno err) { return WriteFile(sock_, &err, sizeof(err)) ? 0 : errno; } diff --git a/util/linux/ptrace_broker.h b/util/linux/ptrace_broker.h index 47dd4d9b..6a7bfb72 100644 --- a/util/linux/ptrace_broker.h +++ b/util/linux/ptrace_broker.h @@ -146,7 +146,7 @@ class PtraceBroker { ThreadInfo info; //! \brief Specifies the success or failure of this call. - Bool success; + ExceptionHandlerProtocol::Bool success; }; #pragma pack(pop) @@ -196,7 +196,7 @@ class PtraceBroker { bool AllocateAttachments(); void ReleaseAttachments(); int RunImpl(); - int SendError(Errno err); + int SendError(ExceptionHandlerProtocol::Errno err); int SendReadError(ReadError err); int SendOpenResult(OpenResult result); int SendFileContents(FileHandle handle); diff --git a/util/linux/ptrace_client.cc b/util/linux/ptrace_client.cc index d822d10e..f0d0d50a 100644 --- a/util/linux/ptrace_client.cc +++ b/util/linux/ptrace_client.cc @@ -31,7 +31,7 @@ namespace crashpad { namespace { bool ReceiveAndLogError(int sock, const std::string& operation) { - Errno error; + ExceptionHandlerProtocol::Errno error; if (!LoggingReadFileExactly(sock, &error, sizeof(error))) { return false; } @@ -69,12 +69,12 @@ bool AttachImpl(int sock, pid_t tid) { return false; } - Bool success; + ExceptionHandlerProtocol::Bool success; if (!LoggingReadFileExactly(sock, &success, sizeof(success))) { return false; } - if (success != kBoolTrue) { + if (success != ExceptionHandlerProtocol::kBoolTrue) { ReceiveAndLogError(sock, "PtraceBroker Attach"); return false; } @@ -159,11 +159,11 @@ bool PtraceClient::Initialize(int sock, pid_t pid, bool try_direct_memory) { return false; } - Bool is_64_bit; + ExceptionHandlerProtocol::Bool is_64_bit; if (!LoggingReadFileExactly(sock_, &is_64_bit, sizeof(is_64_bit))) { return false; } - is_64_bit_ = is_64_bit == kBoolTrue; + is_64_bit_ = is_64_bit == ExceptionHandlerProtocol::kBoolTrue; if (try_direct_memory) { auto direct_mem = std::make_unique<ProcessMemoryLinux>(); @@ -209,7 +209,7 @@ bool PtraceClient::GetThreadInfo(pid_t tid, ThreadInfo* info) { return false; } - if (response.success == kBoolTrue) { + if (response.success == ExceptionHandlerProtocol::kBoolTrue) { *info = response.info; return true; } From 48675b4bd3ddfcdd85b8f2a0ee5abff2226762a4 Mon Sep 17 00:00:00 2001 From: Eric Astor <epastor@google.com> Date: Wed, 24 Apr 2019 11:22:35 -0400 Subject: [PATCH 186/401] Remove pid_t in platform-independent code. Change-Id: Ia58e07bf85a09cd7e63784220800431ad1366584 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1565273 Commit-Queue: Eric Astor <epastor@google.com> Reviewed-by: Mark Mentovai <mark@chromium.org> --- compat/win/sys/types.h | 2 - snapshot/fuchsia/process_snapshot_fuchsia.cc | 4 +- snapshot/fuchsia/process_snapshot_fuchsia.h | 5 +- snapshot/linux/process_snapshot_linux.cc | 4 +- snapshot/linux/process_snapshot_linux.h | 5 +- .../minidump/process_snapshot_minidump.cc | 6 +-- snapshot/minidump/process_snapshot_minidump.h | 7 +-- .../process_snapshot_minidump_test.cc | 2 +- snapshot/process_snapshot.h | 5 +- .../sanitized/process_snapshot_sanitized.cc | 4 +- .../sanitized/process_snapshot_sanitized.h | 5 +- snapshot/test/test_process_snapshot.cc | 4 +- snapshot/test/test_process_snapshot.h | 15 +++--- snapshot/win/process_snapshot_win.cc | 4 +- snapshot/win/process_snapshot_win.h | 5 +- test/win/win_multiprocess_with_temp_dir.cc | 15 +++--- tools/generate_dump.cc | 6 ++- util/BUILD.gn | 1 + util/process/process_id.h | 54 +++++++++++++++++++ util/util.gyp | 1 + util/win/process_info.cc | 4 +- util/win/process_info.h | 9 ++-- 22 files changed, 117 insertions(+), 50 deletions(-) create mode 100644 util/process/process_id.h diff --git a/compat/win/sys/types.h b/compat/win/sys/types.h index fcded87d..e8fae88f 100644 --- a/compat/win/sys/types.h +++ b/compat/win/sys/types.h @@ -20,6 +20,4 @@ #include <stdint.h> -typedef unsigned int pid_t; - #endif // CRASHPAD_COMPAT_WIN_SYS_TYPES_H_ diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.cc b/snapshot/fuchsia/process_snapshot_fuchsia.cc index 59e5d48a..9ae414ef 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia.cc @@ -98,12 +98,12 @@ void ProcessSnapshotFuchsia::GetCrashpadOptions( *options = local_options; } -pid_t ProcessSnapshotFuchsia::ProcessID() const { +crashpad::ProcessID ProcessSnapshotFuchsia::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return GetKoidForHandle(*zx::process::self()); } -pid_t ProcessSnapshotFuchsia::ParentProcessID() const { +crashpad::ProcessID ProcessSnapshotFuchsia::ParentProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196 return 0; diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.h b/snapshot/fuchsia/process_snapshot_fuchsia.h index 35538faa..6af2ebeb 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.h +++ b/snapshot/fuchsia/process_snapshot_fuchsia.h @@ -35,6 +35,7 @@ #include "snapshot/process_snapshot.h" #include "snapshot/unloaded_module_snapshot.h" #include "util/misc/initialization_state_dcheck.h" +#include "util/process/process_id.h" #include "util/process/process_memory_range.h" namespace crashpad { @@ -105,8 +106,8 @@ class ProcessSnapshotFuchsia : public ProcessSnapshot { } // ProcessSnapshot: - pid_t ProcessID() const override; - pid_t ParentProcessID() const override; + crashpad::ProcessID ProcessID() const override; + crashpad::ProcessID ParentProcessID() const override; void SnapshotTime(timeval* snapshot_time) const override; void ProcessStartTime(timeval* start_time) const override; void ProcessCPUTimes(timeval* user_time, timeval* system_time) const override; diff --git a/snapshot/linux/process_snapshot_linux.cc b/snapshot/linux/process_snapshot_linux.cc index 3442e4af..bd95ac7a 100644 --- a/snapshot/linux/process_snapshot_linux.cc +++ b/snapshot/linux/process_snapshot_linux.cc @@ -155,12 +155,12 @@ void ProcessSnapshotLinux::GetCrashpadOptions( *options = local_options; } -pid_t ProcessSnapshotLinux::ProcessID() const { +crashpad::ProcessID ProcessSnapshotLinux::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return process_reader_.ProcessID(); } -pid_t ProcessSnapshotLinux::ParentProcessID() const { +crashpad::ProcessID ProcessSnapshotLinux::ParentProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return process_reader_.ParentProcessID(); } diff --git a/snapshot/linux/process_snapshot_linux.h b/snapshot/linux/process_snapshot_linux.h index c96384d9..705cb5f9 100644 --- a/snapshot/linux/process_snapshot_linux.h +++ b/snapshot/linux/process_snapshot_linux.h @@ -39,6 +39,7 @@ #include "util/linux/ptrace_connection.h" #include "util/misc/initialization_state_dcheck.h" #include "util/misc/uuid.h" +#include "util/process/process_id.h" #include "util/process/process_memory_range.h" namespace crashpad { @@ -106,8 +107,8 @@ class ProcessSnapshotLinux final : public ProcessSnapshot { // ProcessSnapshot: - pid_t ProcessID() const override; - pid_t ParentProcessID() const override; + crashpad::ProcessID ProcessID() const override; + crashpad::ProcessID ParentProcessID() const override; void SnapshotTime(timeval* snapshot_time) const override; void ProcessStartTime(timeval* start_time) const override; void ProcessCPUTimes(timeval* user_time, timeval* system_time) const override; diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 1242b49c..63f653d0 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -58,7 +58,7 @@ ProcessSnapshotMinidump::ProcessSnapshotMinidump() arch_(CPUArchitecture::kCPUArchitectureUnknown), annotations_simple_map_(), file_reader_(nullptr), - process_id_(static_cast<pid_t>(-1)), + process_id_(kInvalidProcessID), initialized_() {} ProcessSnapshotMinidump::~ProcessSnapshotMinidump() {} @@ -120,12 +120,12 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { return true; } -pid_t ProcessSnapshotMinidump::ProcessID() const { +crashpad::ProcessID ProcessSnapshotMinidump::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return process_id_; } -pid_t ProcessSnapshotMinidump::ParentProcessID() const { +crashpad::ProcessID ProcessSnapshotMinidump::ParentProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); NOTREACHED(); // https://crashpad.chromium.org/bug/10 return 0; diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 5713aad8..1deac87f 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -42,6 +42,7 @@ #include "util/file/file_reader.h" #include "util/misc/initialization_state_dcheck.h" #include "util/misc/uuid.h" +#include "util/process/process_id.h" namespace crashpad { @@ -66,8 +67,8 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { // ProcessSnapshot: - pid_t ProcessID() const override; - pid_t ParentProcessID() const override; + crashpad::ProcessID ProcessID() const override; + crashpad::ProcessID ParentProcessID() const override; void SnapshotTime(timeval* snapshot_time) const override; void ProcessStartTime(timeval* start_time) const override; void ProcessCPUTimes(timeval* user_time, timeval* system_time) const override; @@ -151,7 +152,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::map<std::string, std::string> annotations_simple_map_; std::string full_version_; FileReaderInterface* file_reader_; // weak - pid_t process_id_; + crashpad::ProcessID process_id_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ProcessSnapshotMinidump); diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index a471fbca..54ab6eb3 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -544,7 +544,7 @@ TEST(ProcessSnapshotMinidump, ProcessID) { MINIDUMP_HEADER header = {}; ASSERT_TRUE(string_file.Write(&header, sizeof(header))); - static const pid_t kTestProcessId = 42; + static const crashpad::ProcessID kTestProcessId = 42; MINIDUMP_MISC_INFO misc_info = {}; misc_info.SizeOfInfo = sizeof(misc_info); misc_info.Flags1 = MINIDUMP_MISC1_PROCESS_ID; diff --git a/snapshot/process_snapshot.h b/snapshot/process_snapshot.h index f5859d22..08d9f2bc 100644 --- a/snapshot/process_snapshot.h +++ b/snapshot/process_snapshot.h @@ -24,6 +24,7 @@ #include "snapshot/handle_snapshot.h" #include "util/misc/uuid.h" +#include "util/process/process_id.h" namespace crashpad { @@ -50,10 +51,10 @@ class ProcessSnapshot { virtual ~ProcessSnapshot() {} //! \brief Returns the snapshot process’ process ID. - virtual pid_t ProcessID() const = 0; + virtual crashpad::ProcessID ProcessID() const = 0; //! \brief Returns the snapshot process’ parent process’ process ID. - virtual pid_t ParentProcessID() const = 0; + virtual crashpad::ProcessID ParentProcessID() const = 0; //! \brief Returns the time that the snapshot was taken in \a snapshot_time. //! diff --git a/snapshot/sanitized/process_snapshot_sanitized.cc b/snapshot/sanitized/process_snapshot_sanitized.cc index 20807b96..c8d3f67d 100644 --- a/snapshot/sanitized/process_snapshot_sanitized.cc +++ b/snapshot/sanitized/process_snapshot_sanitized.cc @@ -161,12 +161,12 @@ bool ProcessSnapshotSanitized::Initialize( return true; } -pid_t ProcessSnapshotSanitized::ProcessID() const { +crashpad::ProcessID ProcessSnapshotSanitized::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return snapshot_->ProcessID(); } -pid_t ProcessSnapshotSanitized::ParentProcessID() const { +crashpad::ProcessID ProcessSnapshotSanitized::ParentProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return snapshot_->ParentProcessID(); } diff --git a/snapshot/sanitized/process_snapshot_sanitized.h b/snapshot/sanitized/process_snapshot_sanitized.h index b5f0c406..d11c8632 100644 --- a/snapshot/sanitized/process_snapshot_sanitized.h +++ b/snapshot/sanitized/process_snapshot_sanitized.h @@ -29,6 +29,7 @@ #include "util/misc/address_types.h" #include "util/misc/initialization_state_dcheck.h" #include "util/misc/range_set.h" +#include "util/process/process_id.h" namespace crashpad { @@ -66,8 +67,8 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot { // ProcessSnapshot: - pid_t ProcessID() const override; - pid_t ParentProcessID() const override; + crashpad::ProcessID ProcessID() const override; + crashpad::ProcessID ParentProcessID() const override; void SnapshotTime(timeval* snapshot_time) const override; void ProcessStartTime(timeval* start_time) const override; void ProcessCPUTimes(timeval* user_time, timeval* system_time) const override; diff --git a/snapshot/test/test_process_snapshot.cc b/snapshot/test/test_process_snapshot.cc index 1a313705..42a049a5 100644 --- a/snapshot/test/test_process_snapshot.cc +++ b/snapshot/test/test_process_snapshot.cc @@ -42,11 +42,11 @@ TestProcessSnapshot::TestProcessSnapshot() TestProcessSnapshot::~TestProcessSnapshot() { } -pid_t TestProcessSnapshot::ProcessID() const { +crashpad::ProcessID TestProcessSnapshot::ProcessID() const { return process_id_; } -pid_t TestProcessSnapshot::ParentProcessID() const { +crashpad::ProcessID TestProcessSnapshot::ParentProcessID() const { return parent_process_id_; } diff --git a/snapshot/test/test_process_snapshot.h b/snapshot/test/test_process_snapshot.h index bfa26abd..5495cba1 100644 --- a/snapshot/test/test_process_snapshot.h +++ b/snapshot/test/test_process_snapshot.h @@ -35,6 +35,7 @@ #include "snapshot/thread_snapshot.h" #include "snapshot/unloaded_module_snapshot.h" #include "util/misc/uuid.h" +#include "util/process/process_id.h" #include "util/process/process_memory.h" namespace crashpad { @@ -47,8 +48,10 @@ class TestProcessSnapshot final : public ProcessSnapshot { TestProcessSnapshot(); ~TestProcessSnapshot() override; - void SetProcessID(pid_t process_id) { process_id_ = process_id; } - void SetParentProcessID(pid_t parent_process_id) { + void SetProcessID(crashpad::ProcessID process_id) { + process_id_ = process_id; + } + void SetParentProcessID(crashpad::ProcessID parent_process_id) { parent_process_id_ = parent_process_id; } void SetSnapshotTime(const timeval& snapshot_time) { @@ -146,8 +149,8 @@ class TestProcessSnapshot final : public ProcessSnapshot { // ProcessSnapshot: - pid_t ProcessID() const override; - pid_t ParentProcessID() const override; + crashpad::ProcessID ProcessID() const override; + crashpad::ProcessID ParentProcessID() const override; void SnapshotTime(timeval* snapshot_time) const override; void ProcessStartTime(timeval* start_time) const override; void ProcessCPUTimes(timeval* user_time, timeval* system_time) const override; @@ -166,8 +169,8 @@ class TestProcessSnapshot final : public ProcessSnapshot { const ProcessMemory* Memory() const override; private: - pid_t process_id_; - pid_t parent_process_id_; + crashpad::ProcessID process_id_; + crashpad::ProcessID parent_process_id_; timeval snapshot_time_; timeval process_start_time_; timeval process_cpu_user_time_; diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index f91ef29b..d2eef49a 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -123,12 +123,12 @@ void ProcessSnapshotWin::GetCrashpadOptions( *options = options_; } -pid_t ProcessSnapshotWin::ProcessID() const { +crashpad::ProcessID ProcessSnapshotWin::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return process_reader_.GetProcessInfo().ProcessID(); } -pid_t ProcessSnapshotWin::ParentProcessID() const { +crashpad::ProcessID ProcessSnapshotWin::ParentProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return process_reader_.GetProcessInfo().ParentProcessID(); } diff --git a/snapshot/win/process_snapshot_win.h b/snapshot/win/process_snapshot_win.h index 092aaf16..4acfe398 100644 --- a/snapshot/win/process_snapshot_win.h +++ b/snapshot/win/process_snapshot_win.h @@ -44,6 +44,7 @@ #include "snapshot/win/thread_snapshot_win.h" #include "util/misc/initialization_state_dcheck.h" #include "util/misc/uuid.h" +#include "util/process/process_id.h" #include "util/win/address_types.h" #include "util/win/process_structs.h" @@ -112,8 +113,8 @@ class ProcessSnapshotWin final : public ProcessSnapshot { // ProcessSnapshot: - pid_t ProcessID() const override; - pid_t ParentProcessID() const override; + crashpad::ProcessID ProcessID() const override; + crashpad::ProcessID ParentProcessID() const override; void SnapshotTime(timeval* snapshot_time) const override; void ProcessStartTime(timeval* start_time) const override; void ProcessCPUTimes(timeval* user_time, timeval* system_time) const override; diff --git a/test/win/win_multiprocess_with_temp_dir.cc b/test/win/win_multiprocess_with_temp_dir.cc index b61ebf62..ca1e01a5 100644 --- a/test/win/win_multiprocess_with_temp_dir.cc +++ b/test/win/win_multiprocess_with_temp_dir.cc @@ -17,6 +17,7 @@ #include <tlhelp32.h> #include "test/errors.h" +#include "util/process/process_id.h" #include "util/win/process_info.h" namespace crashpad { @@ -28,20 +29,20 @@ constexpr wchar_t kTempDirEnvName[] = L"CRASHPAD_TEST_TEMP_DIR"; // Returns the process IDs of all processes that have |parent_pid| as // parent process ID. -std::vector<pid_t> GetPotentialChildProcessesOf(pid_t parent_pid) { +std::vector<ProcessID> GetPotentialChildProcessesOf(ProcessID parent_pid) { ScopedFileHANDLE snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); if (!snapshot.is_valid()) { ADD_FAILURE() << ErrorMessage("CreateToolhelp32Snapshot"); - return std::vector<pid_t>(); + return std::vector<ProcessID>(); } PROCESSENTRY32 entry = {sizeof(entry)}; if (!Process32First(snapshot.get(), &entry)) { ADD_FAILURE() << ErrorMessage("Process32First"); - return std::vector<pid_t>(); + return std::vector<ProcessID>(); } - std::vector<pid_t> child_pids; + std::vector<ProcessID> child_pids; do { if (entry.th32ParentProcessID == parent_pid) child_pids.push_back(entry.th32ProcessID); @@ -68,11 +69,11 @@ ULARGE_INTEGER GetProcessCreationTime(HANDLE process) { // not their offspring. For this to work without race, |parent| has to be // suspended or have exited. void WaitForAllChildProcessesOf(HANDLE parent) { - pid_t parent_pid = GetProcessId(parent); - std::vector<pid_t> child_pids = GetPotentialChildProcessesOf(parent_pid); + ProcessID parent_pid = GetProcessId(parent); + std::vector<ProcessID> child_pids = GetPotentialChildProcessesOf(parent_pid); ULARGE_INTEGER parent_creationtime = GetProcessCreationTime(parent); - for (pid_t child_pid : child_pids) { + for (ProcessID child_pid : child_pids) { // Try and open the process. This may fail for reasons such as: // 1. The process isn't |parent|'s child process, but rather a // higher-privilege sub-process of an earlier process that had diff --git a/tools/generate_dump.cc b/tools/generate_dump.cc index 35a4e05a..76bb86e4 100644 --- a/tools/generate_dump.cc +++ b/tools/generate_dump.cc @@ -26,6 +26,7 @@ #include "minidump/minidump_file_writer.h" #include "tools/tool_support.h" #include "util/file/file_writer.h" +#include "util/process/process_id.h" #include "util/stdlib/string_number_conversion.h" #if defined(OS_POSIX) @@ -92,7 +93,7 @@ int GenerateDumpMain(int argc, char* argv[]) { struct { std::string dump_path; - pid_t pid; + ProcessID pid; bool suspend; } options = {}; options.suspend = true; @@ -175,7 +176,8 @@ int GenerateDumpMain(int argc, char* argv[]) { #endif // OS_MACOSX if (options.dump_path.empty()) { - options.dump_path = base::StringPrintf("minidump.%d", options.pid); + options.dump_path = base::StringPrintf("minidump.%" PRI_PROCESS_ID, + options.pid); } { diff --git a/util/BUILD.gn b/util/BUILD.gn index f571b863..e984c31e 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -137,6 +137,7 @@ static_library("util") { "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", diff --git a/util/process/process_id.h b/util/process/process_id.h new file mode 100644 index 00000000..113f6fc6 --- /dev/null +++ b/util/process/process_id.h @@ -0,0 +1,54 @@ +// 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_UTIL_PROCESS_PROCESS_ID_H_ +#define CRASHPAD_UTIL_PROCESS_PROCESS_ID_H_ + +#include <type_traits> + +#include "base/format_macros.h" +#include "build/build_config.h" + +#if defined(OS_POSIX) +#include <sys/types.h> +#elif defined(OS_WIN) +#include <windows.h> +#elif defined(OS_FUCHSIA) +#include <zircon/types.h> +#endif + +namespace crashpad { + +#if defined(OS_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<ProcessID, int>::value, "Port."); +#define PRI_PROCESS_ID "d" +#elif defined(OS_WIN) +using ProcessID = DWORD; +constexpr ProcessID kInvalidProcessID = 0; +#define PRI_PROCESS_ID "lu" +#elif defined(OS_FUCHSIA) +using ProcessID = zx_koid_t; +constexpr ProcessID kInvalidProcessID = ZX_KOID_INVALID; +static_assert(std::is_same<ProcessID, int64_t>::value, "Port."); +#define PRI_PROCESS_ID PRId64 +#else +#error Port. +#endif + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_PROCESS_PROCESS_ID_H_ diff --git a/util/util.gyp b/util/util.gyp index 32be8ba9..5c72093f 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -209,6 +209,7 @@ 'posix/signals.h', 'posix/symbolic_constants_posix.cc', 'posix/symbolic_constants_posix.h', + 'process/process_id.h', 'process/process_memory.cc', 'process/process_memory.h', 'process/process_memory_linux.cc', diff --git a/util/win/process_info.cc b/util/win/process_info.cc index ff8f34db..fc0598ed 100644 --- a/util/win/process_info.cc +++ b/util/win/process_info.cc @@ -565,12 +565,12 @@ bool ProcessInfo::IsWow64() const { return is_wow64_; } -pid_t ProcessInfo::ProcessID() const { +crashpad::ProcessID ProcessInfo::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return process_id_; } -pid_t ProcessInfo::ParentProcessID() const { +crashpad::ProcessID ProcessInfo::ParentProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return inherited_from_process_id_; } diff --git a/util/win/process_info.h b/util/win/process_info.h index 58921c56..afbe1462 100644 --- a/util/win/process_info.h +++ b/util/win/process_info.h @@ -24,6 +24,7 @@ #include "base/macros.h" #include "util/misc/initialization_state_dcheck.h" #include "util/numeric/checked_range.h" +#include "util/process/process_id.h" #include "util/stdlib/aligned_allocator.h" #include "util/win/address_types.h" @@ -105,10 +106,10 @@ class ProcessInfo { bool IsWow64() const; //! \return The target process's process ID. - pid_t ProcessID() const; + crashpad::ProcessID ProcessID() const; //! \return The target process's parent process ID. - pid_t ParentProcessID() const; + crashpad::ProcessID ParentProcessID() const; //! \return The command line from the target process's Process Environment //! Block. @@ -173,8 +174,8 @@ class ProcessInfo { // This function is best-effort under low memory conditions. std::vector<Handle> BuildHandleVector(HANDLE process) const; - pid_t process_id_; - pid_t inherited_from_process_id_; + crashpad::ProcessID process_id_; + crashpad::ProcessID inherited_from_process_id_; HANDLE process_; std::wstring command_line_; WinVMAddress peb_address_; From 59cdfbb031dfc82d3273290515676297e971187c Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 29 Apr 2019 14:28:53 -0700 Subject: [PATCH 187/401] linux: support multi client sockets in ExceptionHandlerServer Multi client socket connections allow multiple clients to request crash dumps from a handler process using a single, shared socket connection. This connection mode does not support using a broker process which requires a dedicated socket connection to ensure handler messages aren't intercepted by the wrong clients. The handler uses SIGCONT to indicate to the crasher when a crash dump is complete (or has failed) and may continue. Bug: crashpad:284 Change-Id: I2031029cd254f17497cbf7e7d8740c289581e8aa Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1559306 Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_linux_test.cc | 2 +- handler/handler_main.cc | 4 +- handler/linux/exception_handler_server.cc | 95 +++++++--- handler/linux/exception_handler_server.h | 29 +++- .../linux/exception_handler_server_test.cc | 61 +++++-- util/BUILD.gn | 7 + util/linux/direct_ptrace_connection.cc | 36 +--- util/linux/exception_handler_client.cc | 73 +++++++- util/linux/exception_handler_client.h | 7 +- util/linux/exception_handler_protocol.h | 8 + util/linux/proc_task_reader.cc | 59 +++++++ util/linux/proc_task_reader.h | 34 ++++ util/linux/proc_task_reader_test.cc | 162 ++++++++++++++++++ util/util.gyp | 2 + util/util_test.gyp | 2 + 15 files changed, 498 insertions(+), 83 deletions(-) create mode 100644 util/linux/proc_task_reader.cc create mode 100644 util/linux/proc_task_reader.h create mode 100644 util/linux/proc_task_reader_test.cc diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index 68a49e7c..49206e6c 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -356,7 +356,7 @@ class StartHandlerForClientTest { FromPointerCast<VMAddress>(&sanitization_info); } - ExceptionHandlerClient handler_client(state->client_sock_); + ExceptionHandlerClient handler_client(state->client_sock_, false); CHECK_EQ(handler_client.RequestCrashDump(info), 0); Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr); diff --git a/handler/handler_main.cc b/handler/handler_main.cc index e87d17b7..7820a89d 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -993,8 +993,8 @@ int HandlerMain(int argc, } #elif defined(OS_LINUX) || defined(OS_ANDROID) if (options.initial_client_fd == kInvalidFileHandle || - !exception_handler_server.InitializeWithClient( - ScopedFileHandle(options.initial_client_fd))) { + !exception_handler_server.InitializeWithClient( + ScopedFileHandle(options.initial_client_fd), false)) { return ExitFailure(); } #endif // OS_WIN diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index 4cefd8b4..04f06ffc 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -32,6 +32,7 @@ #include "build/build_config.h" #include "util/file/file_io.h" #include "util/file/filesystem.h" +#include "util/linux/proc_task_reader.h" #include "util/misc/as_underlying_type.h" namespace crashpad { @@ -122,20 +123,48 @@ bool SendMessageToClient( return LoggingWriteFile(client_sock, &message, sizeof(message)); } +int tgkill(pid_t pid, pid_t tid, int signo) { + return syscall(SYS_tgkill, pid, tid, signo); +} + +void SendSIGCONT(pid_t pid, pid_t tid) { + if (tid > 0) { + if (tgkill(pid, tid, ExceptionHandlerProtocol::kDumpDoneSignal) != 0) { + PLOG(ERROR) << "tgkill"; + } + return; + } + + std::vector<pid_t> threads; + if (!ReadThreadIDs(pid, &threads)) { + return; + } + for (const auto& thread : threads) { + if (tgkill(pid, thread, ExceptionHandlerProtocol::kDumpDoneSignal) != 0) { + PLOG(ERROR) << "tgkill"; + } + } +} + class PtraceStrategyDeciderImpl : public PtraceStrategyDecider { public: PtraceStrategyDeciderImpl() : PtraceStrategyDecider() {} ~PtraceStrategyDeciderImpl() = default; - Strategy ChooseStrategy(int sock, const ucred& client_credentials) override { + Strategy ChooseStrategy(int sock, + bool multiple_clients, + const ucred& client_credentials) override { switch (GetPtraceScope()) { case PtraceScope::kClassic: - if (getuid() == client_credentials.uid) { + if (getuid() == client_credentials.uid || HaveCapSysPtrace()) { return Strategy::kDirectPtrace; } - return TryForkingBroker(sock); + return multiple_clients ? Strategy::kNoPtrace : TryForkingBroker(sock); case PtraceScope::kRestricted: + if (multiple_clients) { + return Strategy::kDirectPtrace; + } if (!SendMessageToClient(sock, ExceptionHandlerProtocol:: ServerToClientMessage::kTypeSetPtracer)) { @@ -196,12 +225,6 @@ class PtraceStrategyDeciderImpl : public PtraceStrategyDecider { } // namespace -struct ExceptionHandlerServer::Event { - enum class Type { kShutdown, kClientMessage } type; - - ScopedFileHandle fd; -}; - ExceptionHandlerServer::ExceptionHandlerServer() : clients_(), shutdown_event_(), @@ -217,7 +240,8 @@ void ExceptionHandlerServer::SetPtraceStrategyDecider( strategy_decider_ = std::move(decider); } -bool ExceptionHandlerServer::InitializeWithClient(ScopedFileHandle sock) { +bool ExceptionHandlerServer::InitializeWithClient(ScopedFileHandle sock, + bool multiple_clients) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); pollfd_.reset(epoll_create1(EPOLL_CLOEXEC)); @@ -245,7 +269,9 @@ bool ExceptionHandlerServer::InitializeWithClient(ScopedFileHandle sock) { return false; } - if (!InstallClientSocket(std::move(sock))) { + if (!InstallClientSocket(std::move(sock), + multiple_clients ? Event::Type::kSharedSocketMessage + : Event::Type::kClientMessage)) { return false; } @@ -287,8 +313,8 @@ void ExceptionHandlerServer::Stop() { } void ExceptionHandlerServer::HandleEvent(Event* event, uint32_t event_type) { - DCHECK_EQ(AsUnderlyingType(event->type), - AsUnderlyingType(Event::Type::kClientMessage)); + DCHECK_NE(AsUnderlyingType(event->type), + AsUnderlyingType(Event::Type::kShutdown)); if (event_type & EPOLLERR) { LogSocketError(event->fd.get()); @@ -312,7 +338,8 @@ void ExceptionHandlerServer::HandleEvent(Event* event, uint32_t event_type) { return; } -bool ExceptionHandlerServer::InstallClientSocket(ScopedFileHandle socket) { +bool ExceptionHandlerServer::InstallClientSocket(ScopedFileHandle socket, + Event::Type type) { // The handler may not have permission to set SO_PASSCRED on the socket, but // it doesn't need to if the client has already set it. // https://bugs.chromium.org/p/crashpad/issues/detail?id=252 @@ -334,7 +361,7 @@ bool ExceptionHandlerServer::InstallClientSocket(ScopedFileHandle socket) { } auto event = std::make_unique<Event>(); - event->type = Event::Type::kClientMessage; + event->type = type; event->fd.reset(socket.release()); Event* eventp = event.get(); @@ -421,10 +448,12 @@ bool ExceptionHandlerServer::ReceiveClientMessage(Event* event) { switch (client_msg->type) { case ExceptionHandlerProtocol::ClientToServerMessage::kCrashDumpRequest: - return HandleCrashDumpRequest(msg, - client_msg->client_info, - client_msg->requesting_thread_stack_address, - event->fd.get()); + return HandleCrashDumpRequest( + msg, + client_msg->client_info, + client_msg->requesting_thread_stack_address, + event->fd.get(), + event->type == Event::Type::kSharedSocketMessage); } DCHECK(false); @@ -436,7 +465,8 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( const msghdr& msg, const ExceptionHandlerProtocol::ClientInformation& client_info, VMAddress requesting_thread_stack_address, - int client_sock) { + int client_sock, + bool multiple_clients) { cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); if (cmsg == nullptr) { LOG(ERROR) << "missing credentials"; @@ -460,23 +490,40 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( ucred* client_credentials = reinterpret_cast<ucred*>(CMSG_DATA(cmsg)); pid_t client_process_id = client_credentials->pid; + pid_t requesting_thread_id = -1; - switch (strategy_decider_->ChooseStrategy(client_sock, *client_credentials)) { + switch (strategy_decider_->ChooseStrategy( + client_sock, multiple_clients, *client_credentials)) { case PtraceStrategyDecider::Strategy::kError: + if (multiple_clients) { + SendSIGCONT(client_process_id, requesting_thread_id); + } return false; case PtraceStrategyDecider::Strategy::kNoPtrace: + if (multiple_clients) { + SendSIGCONT(client_process_id, requesting_thread_id); + return true; + } return SendMessageToClient( client_sock, ExceptionHandlerProtocol::ServerToClientMessage:: kTypeCrashDumpFailed); - case PtraceStrategyDecider::Strategy::kDirectPtrace: - delegate_->HandleException( - client_process_id, client_info, requesting_thread_stack_address); + case PtraceStrategyDecider::Strategy::kDirectPtrace: { + delegate_->HandleException(client_process_id, + client_info, + requesting_thread_stack_address, + &requesting_thread_id); + if (multiple_clients) { + SendSIGCONT(client_process_id, requesting_thread_id); + return true; + } break; + } case PtraceStrategyDecider::Strategy::kUseBroker: + DCHECK(!multiple_clients); delegate_->HandleExceptionWithBroker( client_process_id, client_info, client_sock); break; diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index 1b73601c..dfa3e4b5 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -54,9 +54,12 @@ class PtraceStrategyDecider { //! \brief Chooses an appropriate `ptrace` strategy. //! //! \param[in] sock A socket conncted to a ExceptionHandlerClient. + //! \param[in] multiple_clients `true` if the socket is connected to multiple + //! clients. The broker is not supported in this configuration. //! \param[in] client_credentials The credentials for the connected client. //! \return the chosen #Strategy. virtual Strategy ChooseStrategy(int sock, + bool multiple_clients, const ucred& client_credentials) = 0; protected: @@ -122,8 +125,11 @@ class ExceptionHandlerServer { //! This method must be successfully called before Run(). //! //! \param[in] sock A socket on which to receive client requests. + //! \param[in] multiple_clients `true` if this socket is used by multiple + //! clients. Using a broker process is not supported in this + //! configuration. //! \return `true` on success. `false` on failure with a message logged. - bool InitializeWithClient(ScopedFileHandle sock); + bool InitializeWithClient(ScopedFileHandle sock, bool multiple_clients); //! \brief Runs the exception-handling server. //! @@ -143,17 +149,32 @@ class ExceptionHandlerServer { void Stop(); private: - struct Event; + struct Event { + enum class Type { + // Used by Stop() to shutdown the server. + kShutdown, + + // A message from a client on a private socket connection. + kClientMessage, + + // A message from a client on a shared socket connection. + kSharedSocketMessage + }; + + Type type; + ScopedFileHandle fd; + }; void HandleEvent(Event* event, uint32_t event_type); - bool InstallClientSocket(ScopedFileHandle socket); + bool InstallClientSocket(ScopedFileHandle socket, Event::Type type); bool UninstallClientSocket(Event* event); bool ReceiveClientMessage(Event* event); bool HandleCrashDumpRequest( const msghdr& msg, const ExceptionHandlerProtocol::ClientInformation& client_info, VMAddress requesting_thread_stack_address, - int client_sock); + int client_sock, + bool multiple_clients); std::unordered_map<int, std::unique_ptr<Event>> clients_; std::unique_ptr<Event> shutdown_event_; diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index 1c57fce1..7ef007e0 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -18,6 +18,7 @@ #include <unistd.h> #include "base/logging.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "snapshot/linux/process_snapshot_linux.h" #include "test/errors.h" @@ -30,6 +31,10 @@ #include "util/synchronization/semaphore.h" #include "util/thread/thread.h" +#if defined(OS_ANDROID) +#include <android/api-level.h> +#endif + namespace crashpad { namespace test { namespace { @@ -164,7 +169,9 @@ class MockPtraceStrategyDecider : public PtraceStrategyDecider { ~MockPtraceStrategyDecider() {} - Strategy ChooseStrategy(int sock, const ucred& client_credentials) override { + Strategy ChooseStrategy(int sock, + bool multiple_clients, + const ucred& client_credentials) override { if (strategy_ == Strategy::kUseBroker) { ExceptionHandlerProtocol::ServerToClientMessage message = {}; message.type = @@ -194,13 +201,14 @@ class MockPtraceStrategyDecider : public PtraceStrategyDecider { DISALLOW_COPY_AND_ASSIGN(MockPtraceStrategyDecider); }; -class ExceptionHandlerServerTest : public testing::Test { +class ExceptionHandlerServerTest : public testing::TestWithParam<bool> { public: ExceptionHandlerServerTest() : server_(), delegate_(), server_thread_(&server_, &delegate_), - sock_to_handler_() {} + sock_to_handler_(), + use_multi_client_socket_(GetParam()) {} ~ExceptionHandlerServerTest() = default; @@ -243,7 +251,6 @@ class ExceptionHandlerServerTest : public testing::Test { ExceptionHandlerProtocol::ClientInformation info; info.exception_information_address = 42; - ASSERT_TRUE(LoggingWriteFile(WritePipeHandle(), &info, sizeof(info))); // If the current ptrace_scope is restricted, the broker needs to be set @@ -251,7 +258,8 @@ class ExceptionHandlerServerTest : public testing::Test { // ptracer allows the broker to inherit this condition. ScopedPrSetPtracer set_ptracer(getpid(), /* may_log= */ true); - ExceptionHandlerClient client(server_test_->SockToHandler()); + ExceptionHandlerClient client(server_test_->SockToHandler(), + server_test_->use_multi_client_socket_); ASSERT_EQ(client.RequestCrashDump(info), 0); } @@ -274,6 +282,8 @@ class ExceptionHandlerServerTest : public testing::Test { test.Run(); } + bool UsingMultiClientSocket() const { return use_multi_client_socket_; } + protected: void SetUp() override { int socks[2]; @@ -281,7 +291,8 @@ class ExceptionHandlerServerTest : public testing::Test { sock_to_handler_.reset(socks[0]); sock_to_client_ = socks[1]; - ASSERT_TRUE(server_.InitializeWithClient(ScopedFileHandle(socks[1]))); + ASSERT_TRUE(server_.InitializeWithClient(ScopedFileHandle(socks[1]), + use_multi_client_socket_)); } private: @@ -290,36 +301,37 @@ class ExceptionHandlerServerTest : public testing::Test { RunServerThread server_thread_; ScopedFileHandle sock_to_handler_; int sock_to_client_; + bool use_multi_client_socket_; DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServerTest); }; -TEST_F(ExceptionHandlerServerTest, ShutdownWithNoClients) { +TEST_P(ExceptionHandlerServerTest, ShutdownWithNoClients) { ServerThread()->Start(); Hangup(); ASSERT_TRUE(ServerThread()->JoinWithTimeout(5.0)); } -TEST_F(ExceptionHandlerServerTest, StopWithClients) { +TEST_P(ExceptionHandlerServerTest, StopWithClients) { ServerThread()->Start(); Server()->Stop(); ASSERT_TRUE(ServerThread()->JoinWithTimeout(5.0)); } -TEST_F(ExceptionHandlerServerTest, StopBeforeRun) { +TEST_P(ExceptionHandlerServerTest, StopBeforeRun) { Server()->Stop(); ServerThread()->Start(); ASSERT_TRUE(ServerThread()->JoinWithTimeout(5.0)); } -TEST_F(ExceptionHandlerServerTest, MultipleStops) { +TEST_P(ExceptionHandlerServerTest, MultipleStops) { ServerThread()->Start(); Server()->Stop(); Server()->Stop(); ASSERT_TRUE(ServerThread()->JoinWithTimeout(5.0)); } -TEST_F(ExceptionHandlerServerTest, RequestCrashDumpDefault) { +TEST_P(ExceptionHandlerServerTest, RequestCrashDumpDefault) { ScopedStopServerAndJoinThread stop_server(Server(), ServerThread()); ServerThread()->Start(); @@ -327,25 +339,44 @@ TEST_F(ExceptionHandlerServerTest, RequestCrashDumpDefault) { test.Run(); } -TEST_F(ExceptionHandlerServerTest, RequestCrashDumpNoPtrace) { +TEST_P(ExceptionHandlerServerTest, RequestCrashDumpNoPtrace) { ExpectCrashDumpUsingStrategy(PtraceStrategyDecider::Strategy::kNoPtrace, false); } -TEST_F(ExceptionHandlerServerTest, RequestCrashDumpForkBroker) { +TEST_P(ExceptionHandlerServerTest, RequestCrashDumpForkBroker) { + if (UsingMultiClientSocket()) { + // The broker is not supported with multiple clients connected on a single + // socket. + return; + } ExpectCrashDumpUsingStrategy(PtraceStrategyDecider::Strategy::kUseBroker, true); } -TEST_F(ExceptionHandlerServerTest, RequestCrashDumpDirectPtrace) { +TEST_P(ExceptionHandlerServerTest, RequestCrashDumpDirectPtrace) { ExpectCrashDumpUsingStrategy(PtraceStrategyDecider::Strategy::kDirectPtrace, true); } -TEST_F(ExceptionHandlerServerTest, RequestCrashDumpError) { +TEST_P(ExceptionHandlerServerTest, RequestCrashDumpError) { ExpectCrashDumpUsingStrategy(PtraceStrategyDecider::Strategy::kError, false); } +INSTANTIATE_TEST_SUITE_P(ExceptionHandlerServerTestSuite, + ExceptionHandlerServerTest, +#if defined(OS_ANDROID) && __ANDROID_API__ < 23 + // TODO(jperaza): Using a multi-client socket is not + // supported on Android until an lss sigtimedwait() + // wrapper is available to use in + // ExceptionHandlerClient::SignalCrashDump(). + // https://crbug.com/crashpad/265 + testing::Values(false) +#else + testing::Bool() +#endif +); + } // namespace } // namespace test } // namespace crashpad diff --git a/util/BUILD.gn b/util/BUILD.gn index e984c31e..a0023f74 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -295,6 +295,8 @@ static_library("util") { "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", @@ -620,6 +622,7 @@ source_set("util_test") { "linux/auxiliary_vector_test.cc", "linux/memory_map_test.cc", "linux/proc_stat_reader_test.cc", + "linux/proc_task_reader_test.cc", "linux/ptrace_broker_test.cc", "linux/ptracer_test.cc", "linux/scoped_ptrace_attach_test.cc", @@ -668,6 +671,10 @@ source_set("util_test") { "../third_party/zlib", ] + if (crashpad_is_android || crashpad_is_linux) { + deps += [ "../third_party/lss" ] + } + if (!crashpad_is_android) { data_deps = [ ":http_transport_test_server", diff --git a/util/linux/direct_ptrace_connection.cc b/util/linux/direct_ptrace_connection.cc index e757d8f5..8b552055 100644 --- a/util/linux/direct_ptrace_connection.cc +++ b/util/linux/direct_ptrace_connection.cc @@ -14,16 +14,10 @@ #include "util/linux/direct_ptrace_connection.h" -#include <stdio.h> - #include <utility> -#include "base/logging.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "util/file/directory_reader.h" #include "util/file/file_io.h" -#include "util/misc/as_underlying_type.h" +#include "util/linux/proc_task_reader.h" namespace crashpad { @@ -90,33 +84,7 @@ ProcessMemory* DirectPtraceConnection::Memory() { bool DirectPtraceConnection::Threads(std::vector<pid_t>* threads) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - DCHECK(threads->empty()); - - char path[32]; - snprintf(path, base::size(path), "/proc/%d/task", pid_); - DirectoryReader reader; - if (!reader.Open(base::FilePath(path))) { - return false; - } - - std::vector<pid_t> local_threads; - base::FilePath tid_str; - DirectoryReader::Result result; - while ((result = reader.NextFile(&tid_str)) == - DirectoryReader::Result::kSuccess) { - pid_t tid; - if (!base::StringToInt(tid_str.value(), &tid)) { - LOG(ERROR) << "format error"; - continue; - } - - local_threads.push_back(tid); - } - DCHECK_EQ(AsUnderlyingType(result), - AsUnderlyingType(DirectoryReader::Result::kNoMoreFiles)); - - threads->swap(local_threads); - return true; + return ReadThreadIDs(pid_, threads); } } // namespace crashpad diff --git a/util/linux/exception_handler_client.cc b/util/linux/exception_handler_client.cc index 60970695..ca9f2df0 100644 --- a/util/linux/exception_handler_client.cc +++ b/util/linux/exception_handler_client.cc @@ -15,6 +15,7 @@ #include "util/linux/exception_handler_client.h" #include <errno.h> +#include <signal.h> #include <sys/prctl.h> #include <sys/socket.h> #include <sys/wait.h> @@ -28,10 +29,42 @@ #include "util/misc/from_pointer_cast.h" #include "util/posix/signals.h" +#if defined(OS_ANDROID) +#include <android/api-level.h> +#endif + namespace crashpad { -ExceptionHandlerClient::ExceptionHandlerClient(int sock) - : server_sock_(sock), ptracer_(-1), can_set_ptracer_(true) {} +namespace { + +class ScopedSigprocmaskRestore { + public: + explicit ScopedSigprocmaskRestore(const sigset_t& set_to_block) + : orig_mask_(), mask_is_set_(false) { + mask_is_set_ = sigprocmask(SIG_BLOCK, &set_to_block, &orig_mask_) == 0; + DPLOG_IF(ERROR, !mask_is_set_) << "sigprocmask"; + } + + ~ScopedSigprocmaskRestore() { + if (mask_is_set_ && sigprocmask(SIG_SETMASK, &orig_mask_, nullptr) != 0) { + DPLOG(ERROR) << "sigprocmask"; + } + } + + private: + sigset_t orig_mask_; + bool mask_is_set_; + + DISALLOW_COPY_AND_ASSIGN(ScopedSigprocmaskRestore); +}; + +} // namespace + +ExceptionHandlerClient::ExceptionHandlerClient(int sock, bool multiple_clients) + : server_sock_(sock), + ptracer_(-1), + can_set_ptracer_(true), + multiple_clients_(multiple_clients) {} ExceptionHandlerClient::~ExceptionHandlerClient() = default; @@ -39,6 +72,10 @@ int ExceptionHandlerClient::RequestCrashDump( const ExceptionHandlerProtocol::ClientInformation& info) { VMAddress sp = FromPointerCast<VMAddress>(&sp); + if (multiple_clients_) { + return SignalCrashDump(info, sp); + } + int status = SendCrashDumpRequest(info, sp); if (status != 0) { return status; @@ -65,6 +102,38 @@ void ExceptionHandlerClient::SetCanSetPtracer(bool can_set_ptracer) { can_set_ptracer_ = can_set_ptracer; } +int ExceptionHandlerClient::SignalCrashDump( + const ExceptionHandlerProtocol::ClientInformation& info, + VMAddress stack_pointer) { + // TODO(jperaza): Use lss for system calls when sys_sigtimedwait() exists. + // https://crbug.com/crashpad/265 + sigset_t dump_done_sigset; + sigemptyset(&dump_done_sigset); + sigaddset(&dump_done_sigset, ExceptionHandlerProtocol::kDumpDoneSignal); + ScopedSigprocmaskRestore scoped_block(dump_done_sigset); + + int status = SendCrashDumpRequest(info, stack_pointer); + if (status != 0) { + return status; + } + +#if defined(OS_ANDROID) && __ANDROID_API__ < 23 + // sigtimedwait() wrappers aren't available on Android until API 23 but this + // can use the lss wrapper when it's available. + NOTREACHED(); +#else + siginfo_t siginfo = {}; + timespec timeout; + timeout.tv_sec = 5; + timeout.tv_nsec = 0; + if (HANDLE_EINTR(sigtimedwait(&dump_done_sigset, &siginfo, &timeout)) < 0) { + return errno; + } +#endif + + return 0; +} + int ExceptionHandlerClient::SendCrashDumpRequest( const ExceptionHandlerProtocol::ClientInformation& info, VMAddress stack_pointer) { diff --git a/util/linux/exception_handler_client.h b/util/linux/exception_handler_client.h index 6492a12e..10bc2855 100644 --- a/util/linux/exception_handler_client.h +++ b/util/linux/exception_handler_client.h @@ -28,7 +28,9 @@ class ExceptionHandlerClient { //! \brief Constructs this object. //! //! \param[in] sock A socket connected to an ExceptionHandlerServer. - explicit ExceptionHandlerClient(int sock); + //! \param[in] multiple_clients `true` if this socket may be used by multiple + //! clients. + ExceptionHandlerClient(int sock, bool multiple_clients); ~ExceptionHandlerClient(); @@ -56,11 +58,14 @@ class ExceptionHandlerClient { int SendCrashDumpRequest( const ExceptionHandlerProtocol::ClientInformation& info, VMAddress stack_pointer); + int SignalCrashDump(const ExceptionHandlerProtocol::ClientInformation& info, + VMAddress stack_pointer); int WaitForCrashDumpComplete(); int server_sock_; pid_t ptracer_; bool can_set_ptracer_; + bool multiple_clients_; DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerClient); }; diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index d5eb5e88..56f9c39f 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -16,6 +16,7 @@ #define CRASHPAD_UTIL_LINUX_EXCEPTION_HANDLER_PROTOCOL_H_ #include <errno.h> +#include <signal.h> #include <stdint.h> #include <sys/types.h> @@ -51,6 +52,13 @@ class ExceptionHandlerProtocol { VMAddress sanitization_information_address; }; + //! \brief The signal used to indicate a crash dump is complete. + //! + //! When multiple clients share a single socket connection with the handler, + //! the handler sends this signal to the dump requestor to indicate when the + //! the dump is either done or has failed and the client may continue. + static constexpr int kDumpDoneSignal = SIGCONT; + //! \brief The message passed from client to server. struct ClientToServerMessage { static constexpr int32_t kVersion = 1; diff --git a/util/linux/proc_task_reader.cc b/util/linux/proc_task_reader.cc new file mode 100644 index 00000000..360f83a0 --- /dev/null +++ b/util/linux/proc_task_reader.cc @@ -0,0 +1,59 @@ +// 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. + +#include "util/linux/proc_task_reader.h" + +#include <stdio.h> + +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" +#include "util/file/directory_reader.h" +#include "util/misc/as_underlying_type.h" + +namespace crashpad { + +bool ReadThreadIDs(pid_t pid, std::vector<pid_t>* tids) { + DCHECK(tids->empty()); + + char path[32]; + snprintf(path, base::size(path), "/proc/%d/task", pid); + DirectoryReader reader; + if (!reader.Open(base::FilePath(path))) { + return false; + } + + std::vector<pid_t> local_tids; + base::FilePath tid_str; + DirectoryReader::Result result; + while ((result = reader.NextFile(&tid_str)) == + DirectoryReader::Result::kSuccess) { + pid_t tid; + if (!base::StringToInt(tid_str.value(), &tid)) { + LOG(ERROR) << "format error"; + continue; + } + + local_tids.push_back(tid); + } + DCHECK_EQ(AsUnderlyingType(result), + AsUnderlyingType(DirectoryReader::Result::kNoMoreFiles)); + DCHECK(!local_tids.empty()); + + tids->swap(local_tids); + return true; +} + +} // namespace crashpad diff --git a/util/linux/proc_task_reader.h b/util/linux/proc_task_reader.h new file mode 100644 index 00000000..71287d92 --- /dev/null +++ b/util/linux/proc_task_reader.h @@ -0,0 +1,34 @@ +// 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_UTIL_LINUX_PROC_TASK_READER_H_ +#define CRASHPAD_UTIL_LINUX_PROC_TASK_READER_H_ + +#include <sys/types.h> + +#include <vector> + +namespace crashpad { + +//! \brief Enumerates the thread IDs of a process by reading /proc/<pid>/task. +//! +//! \param[in] pid The process ID for which to read thread IDs. +//! \param[out] tids The read thread IDs. +//! \return `true` if the task directory was successfully read. Format errors +//! are logged, but won't cause this function to return `false`. +bool ReadThreadIDs(pid_t pid, std::vector<pid_t>* tids); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_LINUX_PROC_TASK_READER_H_ diff --git a/util/linux/proc_task_reader_test.cc b/util/linux/proc_task_reader_test.cc new file mode 100644 index 00000000..911f6d3d --- /dev/null +++ b/util/linux/proc_task_reader_test.cc @@ -0,0 +1,162 @@ +// 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. + +#include "util/linux/proc_task_reader.h" + +#include "base/logging.h" +#include "base/macros.h" +#include "base/strings/stringprintf.h" +#include "gtest/gtest.h" +#include "test/multiprocess_exec.h" +#include "third_party/lss/lss.h" +#include "util/synchronization/semaphore.h" +#include "util/thread/thread.h" + +namespace crashpad { +namespace test { +namespace { + +bool FindThreadID(pid_t tid, const std::vector<pid_t>& threads) { + for (const auto& thread : threads) { + if (thread == tid) { + return true; + } + } + return false; +} + +class ScopedBlockingThread : public Thread { + public: + ScopedBlockingThread() : tid_sem_(0), join_sem_(0), tid_(-1) {} + + ~ScopedBlockingThread() { + join_sem_.Signal(); + Join(); + } + + pid_t ThreadID() { + tid_sem_.Wait(); + return tid_; + } + + private: + void ThreadMain() override { + tid_ = sys_gettid(); + tid_sem_.Signal(); + join_sem_.Wait(); + } + + Semaphore tid_sem_; + Semaphore join_sem_; + pid_t tid_; +}; + +TEST(ProcTaskReader, Self) { + std::vector<pid_t> tids; + ASSERT_TRUE(ReadThreadIDs(getpid(), &tids)); + EXPECT_TRUE(FindThreadID(getpid(), tids)); + EXPECT_TRUE(FindThreadID(sys_gettid(), tids)); + + ScopedBlockingThread thread1; + thread1.Start(); + + ScopedBlockingThread thread2; + thread2.Start(); + + pid_t thread1_tid = thread1.ThreadID(); + pid_t thread2_tid = thread2.ThreadID(); + + tids.clear(); + ASSERT_TRUE(ReadThreadIDs(getpid(), &tids)); + EXPECT_TRUE(FindThreadID(getpid(), tids)); + EXPECT_TRUE(FindThreadID(thread1_tid, tids)); + EXPECT_TRUE(FindThreadID(thread2_tid, tids)); +} + +TEST(ProcTaskReader, BadPID) { + std::vector<pid_t> tids; + EXPECT_FALSE(ReadThreadIDs(-1, &tids)); + + tids.clear(); + EXPECT_FALSE(ReadThreadIDs(0, &tids)); +} + +CRASHPAD_CHILD_TEST_MAIN(ProcTaskTestChild) { + FileHandle in = StdioFileHandle(StdioStream::kStandardInput); + FileHandle out = StdioFileHandle(StdioStream::kStandardOutput); + + pid_t tid = getpid(); + CheckedWriteFile(out, &tid, sizeof(tid)); + + tid = sys_gettid(); + CheckedWriteFile(out, &tid, sizeof(tid)); + + ScopedBlockingThread thread1; + thread1.Start(); + + ScopedBlockingThread thread2; + thread2.Start(); + + tid = thread1.ThreadID(); + CheckedWriteFile(out, &tid, sizeof(tid)); + + tid = thread2.ThreadID(); + CheckedWriteFile(out, &tid, sizeof(tid)); + + CheckedReadFileAtEOF(in); + return 0; +} + +class ProcTaskTest : public MultiprocessExec { + public: + ProcTaskTest() : MultiprocessExec() { + SetChildTestMainFunction("ProcTaskTestChild"); + } + + private: + bool ReadIDFromChild(std::vector<pid_t>* threads) { + pid_t tid; + if (!LoggingReadFileExactly(ReadPipeHandle(), &tid, sizeof(tid))) { + return false; + } + threads->push_back(tid); + return true; + } + + void MultiprocessParent() override { + std::vector<pid_t> ids_to_find; + for (size_t id_count = 0; id_count < 4; ++id_count) { + ASSERT_TRUE(ReadIDFromChild(&ids_to_find)); + } + + std::vector<pid_t> threads; + ASSERT_TRUE(ReadThreadIDs(ChildPID(), &threads)); + for (size_t index = 0; index < ids_to_find.size(); ++index) { + SCOPED_TRACE( + base::StringPrintf("index %zd, tid %d", index, ids_to_find[index])); + EXPECT_TRUE(FindThreadID(ids_to_find[index], threads)); + } + } + + DISALLOW_COPY_AND_ASSIGN(ProcTaskTest); +}; + +TEST(ProcTaskReader, ReadChild) { + ProcTaskTest test; + test.Run(); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/util.gyp b/util/util.gyp index 5c72093f..f75e96a2 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -67,6 +67,8 @@ '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', diff --git a/util/util_test.gyp b/util/util_test.gyp index 9edd3dcb..619d40f1 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -28,6 +28,7 @@ '../test/test.gyp:crashpad_test', '../third_party/gtest/gmock.gyp:gmock', '../third_party/gtest/gtest.gyp:gtest', + '../third_party/lss/lss.gyp:lss', '../third_party/mini_chromium/mini_chromium.gyp:base', '../third_party/zlib/zlib.gyp:zlib', ], @@ -44,6 +45,7 @@ 'linux/auxiliary_vector_test.cc', 'linux/memory_map_test.cc', 'linux/proc_stat_reader_test.cc', + 'linux/proc_task_reader_test.cc', 'linux/ptrace_broker_test.cc', 'linux/ptracer_test.cc', 'linux/scoped_ptrace_attach_test.cc', From a11243e8f12a2d9a8c5c3b4b68c7f2b9cc6baa42 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 2 May 2019 13:55:08 -0700 Subject: [PATCH 188/401] linux: add wrappers for send/recvmsg sendmsg() and recvmsg() are complicated to use. Refactor their usage into functions with a simpler, tested interface and use those instead. This also adds CreateCredentialSocketpair() to create a pair of connected sockets with SO_PASSCRED set. This option should be set before the possibility of any calls to sendmsg() with the socket pair to avoid race conditions in properly setting credentials. Also update the handler to use Strategy::kNoPtrace (which causes the crash dump to fail without breaking the socket connection) if the credentials were invalid, which can happen if SO_PASSCRED was set after the call to sendmsg() or if the sending process does not exist in this namespace. Change-Id: Id09f87125540255687a3c35d5bed7fa01ec07cff Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1584639 Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_linux_test.cc | 14 +- handler/linux/exception_handler_server.cc | 88 ++-------- handler/linux/exception_handler_server.h | 2 +- util/BUILD.gn | 7 + util/linux/exception_handler_client.cc | 35 +--- util/linux/socket.cc | 192 ++++++++++++++++++++++ util/linux/socket.h | 92 +++++++++++ util/linux/socket_test.cc | 139 ++++++++++++++++ util/util.gyp | 3 + util/util_test.gyp | 1 + 10 files changed, 457 insertions(+), 116 deletions(-) create mode 100644 util/linux/socket.cc create mode 100644 util/linux/socket.h create mode 100644 util/linux/socket_test.cc diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index 49206e6c..f4934239 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -16,7 +16,6 @@ #include <dlfcn.h> #include <stdlib.h> -#include <sys/socket.h> #include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> @@ -38,6 +37,7 @@ #include "util/file/filesystem.h" #include "util/linux/exception_handler_client.h" #include "util/linux/exception_information.h" +#include "util/linux/socket.h" #include "util/misc/address_types.h" #include "util/misc/from_pointer_cast.h" #include "util/posix/signals.h" @@ -245,16 +245,8 @@ class StartHandlerForClientTest { bool Initialize(bool sanitize) { sanitize_ = sanitize; - - int socks[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) != 0) { - PLOG(ERROR) << "socketpair"; - return false; - } - client_sock_.reset(socks[0]); - server_sock_.reset(socks[1]); - - return true; + return UnixCredentialSocket::CreateCredentialSocketpair(&client_sock_, + &server_sock_); } bool StartHandlerOnDemand() { diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index 04f06ffc..2ee1bc8d 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -33,6 +33,7 @@ #include "util/file/file_io.h" #include "util/file/filesystem.h" #include "util/linux/proc_task_reader.h" +#include "util/linux/socket.h" #include "util/misc/as_underlying_type.h" namespace crashpad { @@ -154,6 +155,11 @@ class PtraceStrategyDeciderImpl : public PtraceStrategyDecider { Strategy ChooseStrategy(int sock, bool multiple_clients, const ucred& client_credentials) override { + if (client_credentials.pid <= 0) { + LOG(ERROR) << "invalid credentials"; + return Strategy::kNoPtrace; + } + switch (GetPtraceScope()) { case PtraceScope::kClassic: if (getuid() == client_credentials.uid || HaveCapSysPtrace()) { @@ -402,56 +408,18 @@ bool ExceptionHandlerServer::UninstallClientSocket(Event* event) { bool ExceptionHandlerServer::ReceiveClientMessage(Event* event) { ExceptionHandlerProtocol::ClientToServerMessage message; - iovec iov; - iov.iov_base = &message; - iov.iov_len = sizeof(message); - - msghdr msg; - msg.msg_name = nullptr; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - char cmsg_buf[CMSG_SPACE(sizeof(ucred))]; - msg.msg_control = cmsg_buf; - msg.msg_controllen = sizeof(cmsg_buf); - msg.msg_flags = 0; - - int res = HANDLE_EINTR(recvmsg(event->fd.get(), &msg, 0)); - if (res < 0) { - PLOG(ERROR) << "recvmsg"; - return false; - } - if (res == 0) { - // The client had an orderly shutdown. + ucred creds; + if (!UnixCredentialSocket::RecvMsg( + event->fd.get(), &message, sizeof(message), &creds)) { return false; } - if (msg.msg_name != nullptr || msg.msg_namelen != 0) { - LOG(ERROR) << "unexpected msg name"; - return false; - } - - if (msg.msg_iovlen != 1) { - LOG(ERROR) << "unexpected iovlen"; - return false; - } - - if (msg.msg_iov[0].iov_len != - sizeof(ExceptionHandlerProtocol::ClientToServerMessage)) { - LOG(ERROR) << "unexpected message size " << msg.msg_iov[0].iov_len; - return false; - } - auto client_msg = - reinterpret_cast<ExceptionHandlerProtocol::ClientToServerMessage*>( - msg.msg_iov[0].iov_base); - - switch (client_msg->type) { + switch (message.type) { case ExceptionHandlerProtocol::ClientToServerMessage::kCrashDumpRequest: return HandleCrashDumpRequest( - msg, - client_msg->client_info, - client_msg->requesting_thread_stack_address, + creds, + message.client_info, + message.requesting_thread_stack_address, event->fd.get(), event->type == Event::Type::kSharedSocketMessage); } @@ -462,38 +430,16 @@ bool ExceptionHandlerServer::ReceiveClientMessage(Event* event) { } bool ExceptionHandlerServer::HandleCrashDumpRequest( - const msghdr& msg, + const ucred& creds, const ExceptionHandlerProtocol::ClientInformation& client_info, VMAddress requesting_thread_stack_address, int client_sock, bool multiple_clients) { - cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg == nullptr) { - LOG(ERROR) << "missing credentials"; - return false; - } - - if (cmsg->cmsg_level != SOL_SOCKET) { - LOG(ERROR) << "unexpected cmsg_level " << cmsg->cmsg_level; - return false; - } - - if (cmsg->cmsg_type != SCM_CREDENTIALS) { - LOG(ERROR) << "unexpected cmsg_type " << cmsg->cmsg_type; - return false; - } - - if (cmsg->cmsg_len != CMSG_LEN(sizeof(ucred))) { - LOG(ERROR) << "unexpected cmsg_len " << cmsg->cmsg_len; - return false; - } - - ucred* client_credentials = reinterpret_cast<ucred*>(CMSG_DATA(cmsg)); - pid_t client_process_id = client_credentials->pid; + pid_t client_process_id = creds.pid; pid_t requesting_thread_id = -1; - switch (strategy_decider_->ChooseStrategy( - client_sock, multiple_clients, *client_credentials)) { + switch ( + strategy_decider_->ChooseStrategy(client_sock, multiple_clients, creds)) { case PtraceStrategyDecider::Strategy::kError: if (multiple_clients) { SendSIGCONT(client_process_id, requesting_thread_id); diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index dfa3e4b5..9752195e 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -170,7 +170,7 @@ class ExceptionHandlerServer { bool UninstallClientSocket(Event* event); bool ReceiveClientMessage(Event* event); bool HandleCrashDumpRequest( - const msghdr& msg, + const ucred& creds, const ExceptionHandlerProtocol::ClientInformation& client_info, VMAddress requesting_thread_stack_address, int client_sock, diff --git a/util/BUILD.gn b/util/BUILD.gn index a0023f74..620ae255 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -310,6 +310,8 @@ static_library("util") { "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", @@ -472,6 +474,10 @@ static_library("util") { if (crashpad_is_fuchsia) { public_deps += [ "../third_party/fuchsia" ] } + + if (crashpad_is_android || crashpad_is_linux) { + deps += [ "../third_party/lss" ] + } } if (crashpad_use_boringssl_for_http_transport_socket) { @@ -626,6 +632,7 @@ source_set("util_test") { "linux/ptrace_broker_test.cc", "linux/ptracer_test.cc", "linux/scoped_ptrace_attach_test.cc", + "linux/socket_test.cc", "misc/capture_context_test_util_linux.cc", ] } diff --git a/util/linux/exception_handler_client.cc b/util/linux/exception_handler_client.cc index ca9f2df0..0d01ca31 100644 --- a/util/linux/exception_handler_client.cc +++ b/util/linux/exception_handler_client.cc @@ -17,7 +17,6 @@ #include <errno.h> #include <signal.h> #include <sys/prctl.h> -#include <sys/socket.h> #include <sys/wait.h> #include <unistd.h> @@ -26,6 +25,7 @@ #include "build/build_config.h" #include "util/file/file_io.h" #include "util/linux/ptrace_broker.h" +#include "util/linux/socket.h" #include "util/misc/from_pointer_cast.h" #include "util/posix/signals.h" @@ -142,38 +142,7 @@ int ExceptionHandlerClient::SendCrashDumpRequest( ExceptionHandlerProtocol::ClientToServerMessage::kCrashDumpRequest; message.requesting_thread_stack_address = stack_pointer; message.client_info = info; - - iovec iov; - iov.iov_base = &message; - iov.iov_len = sizeof(message); - - msghdr msg; - msg.msg_name = nullptr; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - ucred creds; - creds.pid = getpid(); - creds.uid = geteuid(); - creds.gid = getegid(); - - char cmsg_buf[CMSG_SPACE(sizeof(creds))]; - msg.msg_control = cmsg_buf; - msg.msg_controllen = sizeof(cmsg_buf); - - cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_CREDENTIALS; - cmsg->cmsg_len = CMSG_LEN(sizeof(creds)); - *reinterpret_cast<ucred*>(CMSG_DATA(cmsg)) = creds; - - if (HANDLE_EINTR(sendmsg(server_sock_, &msg, MSG_NOSIGNAL)) < 0) { - PLOG(ERROR) << "sendmsg"; - return errno; - } - - return 0; + return UnixCredentialSocket::SendMsg(server_sock_, &message, sizeof(message)); } int ExceptionHandlerClient::WaitForCrashDumpComplete() { diff --git a/util/linux/socket.cc b/util/linux/socket.cc new file mode 100644 index 00000000..68efd570 --- /dev/null +++ b/util/linux/socket.cc @@ -0,0 +1,192 @@ +// 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. + +#include "util/linux/socket.h" + +#include <unistd.h> + +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "third_party/lss/lss.h" + +namespace crashpad { + +// static +bool UnixCredentialSocket::CreateCredentialSocketpair(ScopedFileHandle* sock1, + ScopedFileHandle* sock2) { + int socks[2]; + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socks) != 0) { + PLOG(ERROR) << "socketpair"; + return false; + } + ScopedFileHandle local_sock1(socks[0]); + ScopedFileHandle local_sock2(socks[1]); + + int optval = 1; + socklen_t optlen = sizeof(optval); + if (setsockopt(local_sock1.get(), SOL_SOCKET, SO_PASSCRED, &optval, optlen) != + 0 || + setsockopt(local_sock2.get(), SOL_SOCKET, SO_PASSCRED, &optval, optlen) != + 0) { + PLOG(ERROR) << "setsockopt"; + return false; + } + + sock1->swap(local_sock1); + sock2->swap(local_sock2); + return true; +} + +constexpr size_t UnixCredentialSocket::kMaxSendRecvMsgFDs = 4; + +// static +int UnixCredentialSocket::SendMsg(int fd, + const void* buf, + size_t buf_size, + const int* fds, + size_t fd_count) { + // This function is intended to be used after a crash. fds is an integer + // array instead of a vector to avoid forcing callers to provide a vector, + // which they would have to create prior to the crash. + if (fds && fd_count > kMaxSendRecvMsgFDs) { + DLOG(ERROR) << "too many fds " << fd_count; + return EINVAL; + } + + iovec iov; + iov.iov_base = const_cast<void*>(buf); + iov.iov_len = buf_size; + + msghdr msg = {}; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + char cmsg_buf[CMSG_SPACE(sizeof(int) * kMaxSendRecvMsgFDs)]; + if (fds) { + msg.msg_control = cmsg_buf; + msg.msg_controllen = CMSG_SPACE(sizeof(int) * fd_count); + + cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); + DCHECK(cmsg); + + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fd_count); + memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * fd_count); + } + + // TODO(jperaza): Use sys_sendmsg when lss has macros for maniuplating control + // messages. https://crbug.com/crashpad/265 + if (HANDLE_EINTR(sendmsg(fd, &msg, MSG_NOSIGNAL)) < 0) { + DPLOG(ERROR) << "sendmsg"; + return errno; + } + return 0; +} + +// static +bool UnixCredentialSocket::RecvMsg(int fd, + void* buf, + size_t buf_size, + ucred* creds, + std::vector<ScopedFileHandle>* fds) { + iovec iov; + iov.iov_base = buf; + iov.iov_len = buf_size; + + msghdr msg = {}; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + char cmsg_buf[CMSG_SPACE(sizeof(ucred)) + + CMSG_SPACE(sizeof(int) * kMaxSendRecvMsgFDs)]; + msg.msg_control = cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); + + int res = HANDLE_EINTR(recvmsg(fd, &msg, 0)); + if (res < 0) { + PLOG(ERROR) << "recvmsg"; + return false; + } + + ucred* local_creds = nullptr; + std::vector<ScopedFileHandle> local_fds; + bool unhandled_cmsgs = false; + + for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); + cmsg; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int* fdp = reinterpret_cast<int*>(CMSG_DATA(cmsg)); + size_t fd_count = (reinterpret_cast<char*>(cmsg) + cmsg->cmsg_len - + reinterpret_cast<char*>(fdp)) / + sizeof(int); + DCHECK_LE(fd_count, kMaxSendRecvMsgFDs); + for (size_t index = 0; index < fd_count; ++index) { + if (fds) { + local_fds.emplace_back(fdp[index]); + } else if (IGNORE_EINTR(close(fdp[index])) != 0) { + PLOG(ERROR) << "close"; + } + } + continue; + } + + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { + DCHECK(!local_creds); + local_creds = reinterpret_cast<ucred*>(CMSG_DATA(cmsg)); + continue; + } + + LOG(ERROR) << "unhandled cmsg " << cmsg->cmsg_level << ", " + << cmsg->cmsg_type; + unhandled_cmsgs = true; + } + + if (unhandled_cmsgs) { + return false; + } + + if (msg.msg_name != nullptr || msg.msg_namelen != 0) { + LOG(ERROR) << "unexpected msg name"; + return false; + } + + if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) { + LOG(ERROR) << "truncated msg"; + return false; + } + + if (!local_creds) { + LOG(ERROR) << "missing credentials"; + return false; + } + + // res == 0 may also indicate that the sending socket disconnected, but in + // that case, the message will also have missing or invalid credentials. + if (static_cast<size_t>(res) != buf_size) { + if (res != 0 || (local_creds && local_creds->pid != 0)) { + LOG(ERROR) << "incorrect payload size " << res; + } + return false; + } + + *creds = *local_creds; + if (fds) { + fds->swap(local_fds); + } + return true; +} + +} // namespace crashpad diff --git a/util/linux/socket.h b/util/linux/socket.h new file mode 100644 index 00000000..c02a6c30 --- /dev/null +++ b/util/linux/socket.h @@ -0,0 +1,92 @@ +// 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_UTIL_LINUX_SOCKET_H_ +#define CRASHPAD_UTIL_LINUX_SOCKET_H_ + +#include <sys/socket.h> +#include <sys/types.h> + +#include <vector> + +#include "base/macros.h" +#include "util/file/file_io.h" + +namespace crashpad { + +//! \brief Utilities for communicating over `SO_PASSCRED` enabled `AF_UNIX` +//! sockets. +class UnixCredentialSocket { + public: + //! \brief Creates an `AF_UNIX` family socket pair with `SO_PASSCRED` set on + //! each socket. + //! + //! \param[out] s1 One end of the connected pair. + //! \param[out] s2 The other end of the connected pair. + //! \return `true` on success. Otherwise, `false` with a message logged. + static bool CreateCredentialSocketpair(ScopedFileHandle* s1, + ScopedFileHandle* s2); + + //! \brief The maximum number of file descriptors that may be sent/received + //! with `SendMsg()` or `RecvMsg()`. + static const size_t kMaxSendRecvMsgFDs; + + //! \brief Wraps `sendmsg()` to send a message with file descriptors. + //! + //! This function is intended for use with `AF_UNIX` family sockets and + //! passes file descriptors with `SCM_RIGHTS`. + //! + //! This function may be used in a compromised context. + //! + //! \param[in] fd The file descriptor to write the message to. + //! \param[in] buf The buffer containing the message. + //! \param[in] buf_size The size of the message. + //! \param[in] fds An array of at most `kMaxSendRecvMsgFDs` file descriptors. + //! Optional. + //! \param[in] fd_count The number of file descriptors in \a fds. Required + //! only if \a fds was set. + //! \return 0 on success or an error code on failure. + static int SendMsg(int fd, + const void* buf, + size_t buf_size, + const int* fds = nullptr, + size_t fd_count = 0); + + //! \brief Wraps `recvmsg()` to receive a message with file descriptors and + //! credentials. + //! + //! This function is intended to be used with `AF_UNIX` family sockets. Up to + //! `kMaxSendRecvMsgFDs` file descriptors may be received (via `SCM_RIGHTS`). + //! The socket must have `SO_PASSCRED` set. + //! + //! \param[in] fd The file descriptor to receive the message on. + //! \param[out] buf The buffer to fill with the message. + //! \param[in] buf_size The size of the message. + //! \param[out] creds The credentials of the sender. + //! \param[out] fds The recieved file descriptors. Optional. If `nullptr`, all + //! received file descriptors will be closed. + //! \return `true` on success. Otherwise, `false`, with a message logged. + static bool RecvMsg(int fd, + void* buf, + size_t buf_size, + ucred* creds, + std::vector<ScopedFileHandle>* fds = nullptr); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(UnixCredentialSocket); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_LINUX_SOCKET_H_ diff --git a/util/linux/socket_test.cc b/util/linux/socket_test.cc new file mode 100644 index 00000000..4e583aed --- /dev/null +++ b/util/linux/socket_test.cc @@ -0,0 +1,139 @@ +// 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. + +#include "util/linux/socket.h" + +#include "base/logging.h" +#include "base/macros.h" +#include "base/posix/eintr_wrapper.h" +#include "gtest/gtest.h" +#include "util/linux/socket.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(Socket, Credentials) { + ScopedFileHandle send_sock, recv_sock; + ASSERT_TRUE( + UnixCredentialSocket::CreateCredentialSocketpair(&send_sock, &recv_sock)); + + char msg = 42; + ASSERT_EQ(UnixCredentialSocket::SendMsg(send_sock.get(), &msg, sizeof(msg)), + 0); + + char recv_msg = 0; + ucred creds; + ASSERT_TRUE(UnixCredentialSocket::RecvMsg( + recv_sock.get(), &recv_msg, sizeof(recv_msg), &creds)); + EXPECT_EQ(recv_msg, msg); + EXPECT_EQ(creds.pid, getpid()); + EXPECT_EQ(creds.uid, geteuid()); + EXPECT_EQ(creds.gid, getegid()); +} + +TEST(Socket, EmptyMessages) { + ScopedFileHandle send_sock, recv_sock; + ASSERT_TRUE( + UnixCredentialSocket::CreateCredentialSocketpair(&send_sock, &recv_sock)); + + ASSERT_EQ(UnixCredentialSocket::SendMsg(send_sock.get(), nullptr, 0), 0); + + ucred creds; + ASSERT_TRUE( + UnixCredentialSocket::RecvMsg(recv_sock.get(), nullptr, 0, &creds)); + EXPECT_EQ(creds.pid, getpid()); + EXPECT_EQ(creds.uid, geteuid()); + EXPECT_EQ(creds.gid, getegid()); +} + +TEST(Socket, Hangup) { + ScopedFileHandle send_sock, recv_sock; + ASSERT_TRUE( + UnixCredentialSocket::CreateCredentialSocketpair(&send_sock, &recv_sock)); + + send_sock.reset(); + + char recv_msg = 0; + ucred creds; + EXPECT_FALSE(UnixCredentialSocket::RecvMsg( + recv_sock.get(), &recv_msg, sizeof(recv_msg), &creds)); +} + +TEST(Socket, FileDescriptors) { + ScopedFileHandle send_sock, recv_sock; + ASSERT_TRUE( + UnixCredentialSocket::CreateCredentialSocketpair(&send_sock, &recv_sock)); + + ScopedFileHandle test_fd1, test_fd2; + ASSERT_TRUE( + UnixCredentialSocket::CreateCredentialSocketpair(&test_fd1, &test_fd2)); + + char msg = 42; + ASSERT_EQ(UnixCredentialSocket::SendMsg( + send_sock.get(), &msg, sizeof(msg), &test_fd1.get(), 1), + 0); + + char recv_msg = 0; + ucred creds; + std::vector<ScopedFileHandle> fds; + ASSERT_TRUE(UnixCredentialSocket::RecvMsg( + recv_sock.get(), &recv_msg, sizeof(recv_msg), &creds, &fds)); + ASSERT_EQ(fds.size(), 1u); +} + +TEST(Socket, RecvClosesFileDescriptors) { + ScopedFileHandle send_sock, recv_sock; + ASSERT_TRUE( + UnixCredentialSocket::CreateCredentialSocketpair(&send_sock, &recv_sock)); + + ScopedFileHandle send_fds[UnixCredentialSocket::kMaxSendRecvMsgFDs]; + ScopedFileHandle recv_fds[UnixCredentialSocket::kMaxSendRecvMsgFDs]; + int raw_recv_fds[UnixCredentialSocket::kMaxSendRecvMsgFDs]; + for (size_t index = 0; index < UnixCredentialSocket::kMaxSendRecvMsgFDs; + ++index) { + ASSERT_TRUE(UnixCredentialSocket::CreateCredentialSocketpair( + &send_fds[index], &recv_fds[index])); + raw_recv_fds[index] = recv_fds[index].get(); + } + + char msg = 42; + ASSERT_EQ( + UnixCredentialSocket::SendMsg(send_sock.get(), + &msg, + sizeof(msg), + raw_recv_fds, + UnixCredentialSocket::kMaxSendRecvMsgFDs), + 0); + + char recv_msg = 0; + ucred creds; + ASSERT_TRUE(UnixCredentialSocket::RecvMsg( + recv_sock.get(), &recv_msg, sizeof(recv_msg), &creds)); + EXPECT_EQ(creds.pid, getpid()); + + for (size_t index = 0; index < UnixCredentialSocket::kMaxSendRecvMsgFDs; + ++index) { + recv_fds[index].reset(); + char c; + EXPECT_EQ( + HANDLE_EINTR(send(send_fds[index].get(), &c, sizeof(c), MSG_NOSIGNAL)), + -1); + EXPECT_EQ(errno, EPIPE); + } +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/util.gyp b/util/util.gyp index f75e96a2..7efec7dc 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -24,6 +24,7 @@ '../compat/compat.gyp:crashpad_compat', '../third_party/mini_chromium/mini_chromium.gyp:base', '../third_party/zlib/zlib.gyp:zlib', + '../third_party/lss/lss.gyp:lss', ], 'include_dirs': [ '..', @@ -82,6 +83,8 @@ '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', diff --git a/util/util_test.gyp b/util/util_test.gyp index 619d40f1..573162e6 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -49,6 +49,7 @@ 'linux/ptrace_broker_test.cc', 'linux/ptracer_test.cc', 'linux/scoped_ptrace_attach_test.cc', + 'linux/socket_test.cc', 'mac/launchd_test.mm', 'mac/mac_util_test.mm', 'mac/service_management_test.mm', From e23286dc371cac317e00fed3992808a455ae70da Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 1 May 2019 18:55:58 -0700 Subject: [PATCH 189/401] linux: extend handler protocol with credential messages This message type allows the browser to determine the handler's process ID to be used with `prctl(PR_SET_PTRACER, ...)`. Bug: crashpad:284 Change-Id: I2664f3e8aee269b159de9074e389397346c808f0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1577704 Reviewed-by: Mark Mentovai <mark@chromium.org> --- handler/linux/exception_handler_server.cc | 13 ++++++++++++- util/linux/exception_handler_client.cc | 20 +++++++++++++++++++- util/linux/exception_handler_client.h | 12 ++++++++++++ util/linux/exception_handler_protocol.cc | 2 +- util/linux/exception_handler_protocol.h | 22 ++++++++++++++++------ 5 files changed, 60 insertions(+), 9 deletions(-) diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index 2ee1bc8d..ef03696a 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -147,6 +147,14 @@ void SendSIGCONT(pid_t pid, pid_t tid) { } } +bool SendCredentials(int client_sock) { + ExceptionHandlerProtocol::ServerToClientMessage message = {}; + message.type = + ExceptionHandlerProtocol::ServerToClientMessage::kTypeCredentials; + return UnixCredentialSocket::SendMsg( + client_sock, &message, sizeof(message)) == 0; +} + class PtraceStrategyDeciderImpl : public PtraceStrategyDecider { public: PtraceStrategyDeciderImpl() : PtraceStrategyDecider() {} @@ -415,7 +423,10 @@ bool ExceptionHandlerServer::ReceiveClientMessage(Event* event) { } switch (message.type) { - case ExceptionHandlerProtocol::ClientToServerMessage::kCrashDumpRequest: + case ExceptionHandlerProtocol::ClientToServerMessage::kTypeCheckCredentials: + return SendCredentials(event->fd.get()); + + case ExceptionHandlerProtocol::ClientToServerMessage::kTypeCrashDumpRequest: return HandleCrashDumpRequest( creds, message.client_info, diff --git a/util/linux/exception_handler_client.cc b/util/linux/exception_handler_client.cc index 0d01ca31..64ae0067 100644 --- a/util/linux/exception_handler_client.cc +++ b/util/linux/exception_handler_client.cc @@ -68,6 +68,20 @@ ExceptionHandlerClient::ExceptionHandlerClient(int sock, bool multiple_clients) ExceptionHandlerClient::~ExceptionHandlerClient() = default; +bool ExceptionHandlerClient::GetHandlerCredentials(ucred* creds) { + ExceptionHandlerProtocol::ClientToServerMessage message = {}; + message.type = + ExceptionHandlerProtocol::ClientToServerMessage::kTypeCheckCredentials; + if (UnixCredentialSocket::SendMsg(server_sock_, &message, sizeof(message)) != + 0) { + return false; + } + + ExceptionHandlerProtocol::ServerToClientMessage response; + return UnixCredentialSocket::RecvMsg( + server_sock_, &response, sizeof(response), creds); +} + int ExceptionHandlerClient::RequestCrashDump( const ExceptionHandlerProtocol::ClientInformation& info) { VMAddress sp = FromPointerCast<VMAddress>(&sp); @@ -139,7 +153,7 @@ int ExceptionHandlerClient::SendCrashDumpRequest( VMAddress stack_pointer) { ExceptionHandlerProtocol::ClientToServerMessage message; message.type = - ExceptionHandlerProtocol::ClientToServerMessage::kCrashDumpRequest; + ExceptionHandlerProtocol::ClientToServerMessage::kTypeCrashDumpRequest; message.requesting_thread_stack_address = stack_pointer; message.client_info = info; return UnixCredentialSocket::SendMsg(server_sock_, &message, sizeof(message)); @@ -197,6 +211,10 @@ int ExceptionHandlerClient::WaitForCrashDumpComplete() { continue; } + case ExceptionHandlerProtocol::ServerToClientMessage::kTypeCredentials: + DCHECK(false); + continue; + case ExceptionHandlerProtocol::ServerToClientMessage:: kTypeCrashDumpComplete: case ExceptionHandlerProtocol::ServerToClientMessage:: diff --git a/util/linux/exception_handler_client.h b/util/linux/exception_handler_client.h index 10bc2855..4e10fa62 100644 --- a/util/linux/exception_handler_client.h +++ b/util/linux/exception_handler_client.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_UTIL_LINUX_EXCEPTION_HANDLER_CLIENT_H_ #define CRASHPAD_UTIL_LINUX_EXCEPTION_HANDLER_CLIENT_H_ +#include <sys/socket.h> #include <sys/types.h> #include "base/macros.h" @@ -34,6 +35,17 @@ class ExceptionHandlerClient { ~ExceptionHandlerClient(); + //! \brief Communicates with the handler to determine its credentials. + //! + //! If using a multi-client socket, this method should be called before + //! sharing the client socket end, or the handler's response may not be + //! received. + //! + //! \param[out] creds The handler process' credentials, valid if this method + //! returns `true`. + //! \return `true` on success. Otherwise, `false` with a message logged. + bool GetHandlerCredentials(ucred* creds); + //! \brief Request a crash dump from the ExceptionHandlerServer. //! //! This method blocks until the crash dump is complete. diff --git a/util/linux/exception_handler_protocol.cc b/util/linux/exception_handler_protocol.cc index 7ab77d39..31b93222 100644 --- a/util/linux/exception_handler_protocol.cc +++ b/util/linux/exception_handler_protocol.cc @@ -20,6 +20,6 @@ ExceptionHandlerProtocol::ClientInformation::ClientInformation() : exception_information_address(0), sanitization_information_address(0) {} ExceptionHandlerProtocol::ClientToServerMessage::ClientToServerMessage() - : version(kVersion), type(kCrashDumpRequest), client_info() {} + : version(kVersion), type(kTypeCrashDumpRequest), client_info() {} } // namespace crashpad diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index 56f9c39f..7f4da266 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -69,14 +69,19 @@ class ExceptionHandlerProtocol { //! \brief Indicates what message version is being used. int32_t version; + enum Type : uint32_t { + //! \brief Request that the server respond with its credentials. + kTypeCheckCredentials, + + //! \brief Used to request a crash dump for the sending client. + kTypeCrashDumpRequest + }; + + Type type; + //! \brief A stack address of the thread sending the message. VMAddress requesting_thread_stack_address; - enum Type : uint32_t { - //! \brief Used to request a crash dump for the sending client. - kCrashDumpRequest - } type; - union { //! \brief Valid for type == kCrashDumpRequest ClientInformation client_info; @@ -86,6 +91,9 @@ class ExceptionHandlerProtocol { //! \brief The message passed from server to client. struct ServerToClientMessage { enum Type : uint32_t { + //! \brief Used to pass credentials with `SCM_CREDENTIALS`. + kTypeCredentials, + //! \brief Indicates that the client should fork a PtraceBroker process. kTypeForkBroker, @@ -100,7 +108,9 @@ class ExceptionHandlerProtocol { //! \brief Indicicates that the handler was unable to produce a crash //! dump. kTypeCrashDumpFailed - } type; + }; + + Type type; //! \brief The handler's process ID. Valid for kTypeSetPtracer. pid_t pid; From 607c80e0b8f0c0f22e1c5a80402df7ebd9114b19 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 1 May 2019 22:19:21 -0700 Subject: [PATCH 190/401] linux: Implement StartHandler() This CL adds a RequestCrashDumpHandler to request a crash dump over a socket. Common functionality with LaunchAtCrashHandler is factored out into a SignalHandler base class. Bug: crashpad:284 Change-Id: I86293ef599a0dd6eea63c096a5c931c620c05ecc Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1568985 Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client.h | 4 + client/crashpad_client_linux.cc | 245 ++++++++++++++++++--------- client/crashpad_client_linux_test.cc | 154 ++++++++++------- handler/crashpad_handler.md | 42 +++-- handler/handler_main.cc | 92 ++++++---- 5 files changed, 348 insertions(+), 189 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 8bf43acd..3db1c9c1 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -78,6 +78,10 @@ class CrashpadClient { //! On Fuchsia, this method binds to the exception port of the current default //! job, and starts a Crashpad handler to monitor that port. //! + //! On Linux, this method starts a Crashpad handler, connected to this process + //! via an `AF_UNIX` socket pair and installs signal handlers to request crash + //! dumps on the client's socket end. + //! //! \param[in] handler The path to a Crashpad handler executable. //! \param[in] database The path to a Crashpad database. The handler will be //! started with this path as its `--database` argument. diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index b72980c1..008f8587 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -31,6 +31,7 @@ #include "util/linux/exception_information.h" #include "util/linux/scoped_pr_set_dumpable.h" #include "util/linux/scoped_pr_set_ptracer.h" +#include "util/linux/socket.h" #include "util/misc/from_pointer_cast.h" #include "util/posix/double_fork_and_exec.h" #include "util/posix/signals.h" @@ -43,7 +44,7 @@ std::string FormatArgumentInt(const std::string& name, int value) { return base::StringPrintf("--%s=%d", name.c_str(), value); } -std::string FormatArgumentAddress(const std::string& name, void* addr) { +std::string FormatArgumentAddress(const std::string& name, const void* addr) { return base::StringPrintf("--%s=%p", name.c_str(), addr); } @@ -110,8 +111,90 @@ std::vector<std::string> BuildArgsToLaunchWithLinker( #endif // OS_ANDROID +// A base class for Crashpad signal handler implementations. +class SignalHandler { + public: + // Returns the currently installed signal hander. May be `nullptr` if no + // 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; } + + void SetFirstChanceHandler(CrashpadClient::FirstChanceHandler handler) { + first_chance_handler_ = handler; + } + + // 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<ucontext_t*>(context))) { + return true; + } + + exception_information_.siginfo_address = + FromPointerCast<decltype(exception_information_.siginfo_address)>( + siginfo); + exception_information_.context_address = + FromPointerCast<decltype(exception_information_.context_address)>( + context); + exception_information_.thread_id = sys_gettid(); + + HandleCrashImpl(); + return false; + } + + protected: + SignalHandler() = default; + + bool Install() { + DCHECK(!handler_); + handler_ = this; + return Signals::InstallCrashHandlers( + HandleOrReraiseSignal, 0, &old_actions_); + } + + const ExceptionInformation& GetExceptionInfo() { + return exception_information_; + } + + virtual void HandleCrashImpl() = 0; + + private: + // The signal handler installed at OS-level. + static void HandleOrReraiseSignal(int signo, + siginfo_t* siginfo, + void* context) { + if (handler_->HandleCrash(signo, siginfo, context)) { + return; + } + Signals::RestoreHandlerAndReraiseSignalOnReturn( + siginfo, handler_->old_actions_.ActionForSignal(signo)); + } + + Signals::OldActions old_actions_ = {}; + ExceptionInformation exception_information_ = {}; + CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr; + + static SignalHandler* handler_; + + static thread_local bool disabled_for_thread_; + + DISALLOW_COPY_AND_ASSIGN(SignalHandler); +}; +SignalHandler* SignalHandler::handler_ = nullptr; +thread_local bool SignalHandler::disabled_for_thread_ = false; + // Launches a single use handler to snapshot this process. -class LaunchAtCrashHandler { +class LaunchAtCrashHandler : public SignalHandler { public: static LaunchAtCrashHandler* Get() { static LaunchAtCrashHandler* instance = new LaunchAtCrashHandler(); @@ -129,33 +212,19 @@ class LaunchAtCrashHandler { } argv_strings_.push_back(FormatArgumentAddress("trace-parent-with-exception", - &exception_information_)); + &GetExceptionInfo())); StringVectorToCStringVector(argv_strings_, &argv_); - return Signals::InstallCrashHandlers(HandleCrash, 0, &old_actions_); + return Install(); } - bool HandleCrashNonFatal(int signo, siginfo_t* siginfo, void* context) { - if (first_chance_handler_ && - first_chance_handler_( - signo, siginfo, static_cast<ucontext_t*>(context))) { - return true; - } - - exception_information_.siginfo_address = - FromPointerCast<decltype(exception_information_.siginfo_address)>( - siginfo); - exception_information_.context_address = - FromPointerCast<decltype(exception_information_.context_address)>( - context); - exception_information_.thread_id = syscall(SYS_gettid); - + void HandleCrashImpl() override { ScopedPrSetPtracer set_ptracer(sys_getpid(), /* may_log= */ false); ScopedPrSetDumpable set_dumpable(/* may_log= */ false); pid_t pid = fork(); if (pid < 0) { - return false; + return; } if (pid == 0) { if (set_envp_) { @@ -170,52 +239,72 @@ class LaunchAtCrashHandler { int status; waitpid(pid, &status, 0); - return false; } - void HandleCrashFatal(int signo, siginfo_t* siginfo, void* context) { - if (enabled_ && HandleCrashNonFatal(signo, siginfo, context)) { - return; - } - Signals::RestoreHandlerAndReraiseSignalOnReturn( - siginfo, old_actions_.ActionForSignal(signo)); - } - - void SetFirstChanceHandler(CrashpadClient::FirstChanceHandler handler) { - first_chance_handler_ = handler; - } - - static void Disable() { enabled_ = false; } - private: LaunchAtCrashHandler() = default; ~LaunchAtCrashHandler() = delete; - static void HandleCrash(int signo, siginfo_t* siginfo, void* context) { - auto state = Get(); - state->HandleCrashFatal(signo, siginfo, context); - } - - Signals::OldActions old_actions_ = {}; std::vector<std::string> argv_strings_; std::vector<const char*> argv_; std::vector<std::string> envp_strings_; std::vector<const char*> envp_; - ExceptionInformation exception_information_; - CrashpadClient::FirstChanceHandler first_chance_handler_ = nullptr; bool set_envp_ = false; - static thread_local bool enabled_; - DISALLOW_COPY_AND_ASSIGN(LaunchAtCrashHandler); }; -thread_local bool LaunchAtCrashHandler::enabled_ = true; -// A pointer to the currently installed crash signal handler. This allows -// the static method CrashpadClient::DumpWithoutCrashing to simulate a crash -// using the currently configured crash handling strategy. -static LaunchAtCrashHandler* g_crash_handler; +class RequestCrashDumpHandler : public SignalHandler { + public: + static RequestCrashDumpHandler* Get() { + static RequestCrashDumpHandler* instance = new RequestCrashDumpHandler(); + return instance; + } + + // pid < 0 indicates the handler pid should be determined by communicating + // over the socket. + // pid == 0 indicates it is not necessary to set the handler as this process' + // ptracer. e.g. if the handler has CAP_SYS_PTRACE or if this process is in a + // user namespace and the handler's uid matches the uid of the process that + // created the namespace. + // pid > 0 directly indicates what the handler's pid is expected to be, so + // retrieving this information from the handler is not necessary. + bool Initialize(ScopedFileHandle sock, pid_t pid) { + ExceptionHandlerClient client(sock.get(), true); + if (pid < 0) { + ucred creds; + if (!client.GetHandlerCredentials(&creds)) { + return false; + } + pid = creds.pid; + } + if (pid > 0 && client.SetPtracer(pid) != 0) { + LOG(ERROR) << "failed to set ptracer"; + return false; + } + sock_to_handler_.reset(sock.release()); + return Install(); + } + + void HandleCrashImpl() override { + ExceptionHandlerProtocol::ClientInformation info = {}; + info.exception_information_address = + FromPointerCast<VMAddress>(&GetExceptionInfo()); + + ExceptionHandlerClient client(sock_to_handler_.get(), true); + client.RequestCrashDump(info); + } + + private: + RequestCrashDumpHandler() = default; + + ~RequestCrashDumpHandler() = delete; + + ScopedFileHandle sock_to_handler_; + + DISALLOW_COPY_AND_ASSIGN(RequestCrashDumpHandler); +}; } // namespace @@ -232,11 +321,26 @@ bool CrashpadClient::StartHandler( const std::vector<std::string>& arguments, bool restartable, bool asynchronous_start) { - // TODO(jperaza): Implement this after the Android/Linux ExceptionHandlerSever - // supports accepting new connections. - // https://crashpad.chromium.org/bug/30 - NOTREACHED(); - return false; + DCHECK(!restartable); + DCHECK(!asynchronous_start); + + ScopedFileHandle client_sock, handler_sock; + if (!UnixCredentialSocket::CreateCredentialSocketpair(&client_sock, + &handler_sock)) { + return false; + } + + std::vector<std::string> argv = BuildHandlerArgvStrings( + handler, database, metrics_dir, url, annotations, arguments); + + 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)) { + return false; + } + + auto signal_handler = RequestCrashDumpHandler::Get(); + return signal_handler->Initialize(std::move(client_sock), -1); } #if defined(OS_ANDROID) @@ -259,12 +363,7 @@ bool CrashpadClient::StartJavaHandlerAtCrash( kInvalidFileHandle); auto signal_handler = LaunchAtCrashHandler::Get(); - if (signal_handler->Initialize(&argv, env)) { - DCHECK(!g_crash_handler); - g_crash_handler = signal_handler; - return true; - } - return false; + return signal_handler->Initialize(&argv, env); } // static @@ -304,12 +403,7 @@ bool CrashpadClient::StartHandlerWithLinkerAtCrash( arguments, kInvalidFileHandle); auto signal_handler = LaunchAtCrashHandler::Get(); - if (signal_handler->Initialize(&argv, env)) { - DCHECK(!g_crash_handler); - g_crash_handler = signal_handler; - return true; - } - return false; + return signal_handler->Initialize(&argv, env); } // static @@ -351,12 +445,7 @@ bool CrashpadClient::StartHandlerAtCrash( handler, database, metrics_dir, url, annotations, arguments); auto signal_handler = LaunchAtCrashHandler::Get(); - if (signal_handler->Initialize(&argv, nullptr)) { - DCHECK(!g_crash_handler); - g_crash_handler = signal_handler; - return true; - } - return false; + return signal_handler->Initialize(&argv, nullptr); } // static @@ -378,7 +467,7 @@ bool CrashpadClient::StartHandlerForClient( // static void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) { - if (!g_crash_handler) { + if (!SignalHandler::Get()) { DLOG(ERROR) << "Crashpad isn't enabled"; return; } @@ -395,21 +484,21 @@ void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) { siginfo.si_signo = Signals::kSimulatedSigno; siginfo.si_errno = 0; siginfo.si_code = 0; - g_crash_handler->HandleCrashNonFatal( + SignalHandler::Get()->HandleCrash( siginfo.si_signo, &siginfo, reinterpret_cast<void*>(context)); } // static void CrashpadClient::CrashWithoutDump(const std::string& message) { - LaunchAtCrashHandler::Disable(); + SignalHandler::DisableForThread(); LOG(FATAL) << message; } // static void CrashpadClient::SetFirstChanceExceptionHandler( FirstChanceHandler handler) { - DCHECK(g_crash_handler); - g_crash_handler->SetFirstChanceHandler(handler); + DCHECK(SignalHandler::Get()); + SignalHandler::Get()->SetFirstChanceHandler(handler); } } // namespace crashpad diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index f4934239..2ed88251 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -55,59 +55,55 @@ namespace crashpad { namespace test { namespace { +struct StartHandlerForSelfTestOptions { + bool start_handler_at_crash; + bool simulate_crash; + bool set_first_chance_handler; +}; + +class StartHandlerForSelfTest + : public testing::TestWithParam<std::tuple<bool, bool, bool>> { + public: + StartHandlerForSelfTest() = default; + ~StartHandlerForSelfTest() = default; + + void SetUp() override { + std::tie(options_.start_handler_at_crash, + options_.simulate_crash, + options_.set_first_chance_handler) = GetParam(); + } + + const StartHandlerForSelfTestOptions& Options() const { return options_; } + + private: + StartHandlerForSelfTestOptions options_; + + DISALLOW_COPY_AND_ASSIGN(StartHandlerForSelfTest); +}; + bool HandleCrashSuccessfully(int, siginfo_t*, ucontext_t*) { return true; } -TEST(CrashpadClient, SimulateCrash) { - ScopedTempDir temp_dir; - - base::FilePath handler_path = TestPaths::Executable().DirName().Append( - FILE_PATH_LITERAL("crashpad_handler")); - - crashpad::CrashpadClient client; - ASSERT_TRUE(client.StartHandlerAtCrash(handler_path, - base::FilePath(temp_dir.path()), - base::FilePath(), - "", - std::map<std::string, std::string>(), - std::vector<std::string>())); - - auto database = - CrashReportDatabase::InitializeWithoutCreating(temp_dir.path()); - ASSERT_TRUE(database); - - { - CrashpadClient::SetFirstChanceExceptionHandler(HandleCrashSuccessfully); - - CRASHPAD_SIMULATE_CRASH(); - - std::vector<CrashReportDatabase::Report> reports; - ASSERT_EQ(database->GetPendingReports(&reports), - CrashReportDatabase::kNoError); - EXPECT_EQ(reports.size(), 0u); - - reports.clear(); - ASSERT_EQ(database->GetCompletedReports(&reports), - CrashReportDatabase::kNoError); - EXPECT_EQ(reports.size(), 0u); - } - - { - CrashpadClient::SetFirstChanceExceptionHandler(nullptr); - - CRASHPAD_SIMULATE_CRASH(); - - std::vector<CrashReportDatabase::Report> reports; - ASSERT_EQ(database->GetPendingReports(&reports), - CrashReportDatabase::kNoError); - EXPECT_EQ(reports.size(), 1u); - - reports.clear(); - ASSERT_EQ(database->GetCompletedReports(&reports), - CrashReportDatabase::kNoError); - EXPECT_EQ(reports.size(), 0u); - } +bool InstallHandler(CrashpadClient* client, + bool start_at_crash, + const base::FilePath& handler_path, + const base::FilePath& database_path) { + return start_at_crash + ? client->StartHandlerAtCrash(handler_path, + database_path, + base::FilePath(), + "", + std::map<std::string, std::string>(), + std::vector<std::string>()) + : client->StartHandler(handler_path, + database_path, + base::FilePath(), + "", + std::map<std::string, std::string>(), + std::vector<std::string>(), + false, + false); } constexpr char kTestAnnotationName[] = "name_of_annotation"; @@ -152,7 +148,7 @@ void ValidateDump(const CrashReportDatabase::UploadReport* report) { ADD_FAILURE(); } -CRASHPAD_CHILD_TEST_MAIN(StartHandlerAtCrashChild) { +CRASHPAD_CHILD_TEST_MAIN(StartHandlerForSelfTestChild) { FileHandle in = StdioFileHandle(StdioStream::kStandardInput); VMSize temp_dir_length; @@ -161,6 +157,9 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerAtCrashChild) { std::string temp_dir(temp_dir_length, '\0'); CheckedReadFileExactly(in, &temp_dir[0], temp_dir_length); + StartHandlerForSelfTestOptions options; + CheckedReadFileExactly(in, &options, sizeof(options)); + base::FilePath handler_path = TestPaths::Executable().DirName().Append( FILE_PATH_LITERAL("crashpad_handler")); @@ -170,12 +169,10 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerAtCrashChild) { test_annotation.Set(kTestAnnotationValue); crashpad::CrashpadClient client; - if (!client.StartHandlerAtCrash(handler_path, - base::FilePath(temp_dir), - base::FilePath(), - "", - std::map<std::string, std::string>(), - std::vector<std::string>())) { + if (!InstallHandler(&client, + options.start_handler_at_crash, + handler_path, + base::FilePath(temp_dir))) { return EXIT_FAILURE; } @@ -185,17 +182,28 @@ CRASHPAD_CHILD_TEST_MAIN(StartHandlerAtCrashChild) { } #endif + if (options.simulate_crash) { + if (options.set_first_chance_handler) { + client.SetFirstChanceExceptionHandler(HandleCrashSuccessfully); + } + CRASHPAD_SIMULATE_CRASH(); + return EXIT_SUCCESS; + } + __builtin_trap(); NOTREACHED(); return EXIT_SUCCESS; } -class StartHandlerAtCrashTest : public MultiprocessExec { +class StartHandlerForSelfInChildTest : public MultiprocessExec { public: - StartHandlerAtCrashTest() : MultiprocessExec() { - SetChildTestMainFunction("StartHandlerAtCrashChild"); - SetExpectedChildTerminationBuiltinTrap(); + StartHandlerForSelfInChildTest(const StartHandlerForSelfTestOptions& options) + : MultiprocessExec(), options_(options) { + SetChildTestMainFunction("StartHandlerForSelfTestChild"); + if (!options.simulate_crash) { + SetExpectedChildTerminationBuiltinTrap(); + } } private: @@ -206,6 +214,8 @@ class StartHandlerAtCrashTest : public MultiprocessExec { WritePipeHandle(), &temp_dir_length, sizeof(temp_dir_length))); ASSERT_TRUE(LoggingWriteFile( WritePipeHandle(), temp_dir.path().value().data(), temp_dir_length)); + ASSERT_TRUE( + LoggingWriteFile(WritePipeHandle(), &options_, sizeof(options_))); // Wait for child to finish. CheckedReadFileAtEOF(ReadPipeHandle()); @@ -221,7 +231,11 @@ class StartHandlerAtCrashTest : public MultiprocessExec { reports.clear(); ASSERT_EQ(database->GetPendingReports(&reports), CrashReportDatabase::kNoError); - ASSERT_EQ(reports.size(), 1u); + ASSERT_EQ(reports.size(), options_.set_first_chance_handler ? 0u : 1u); + + if (options_.set_first_chance_handler) { + return; + } std::unique_ptr<const CrashReportDatabase::UploadReport> report; ASSERT_EQ(database->GetReportForUploading(reports[0].uuid, &report), @@ -229,14 +243,26 @@ class StartHandlerAtCrashTest : public MultiprocessExec { ValidateDump(report.get()); } - DISALLOW_COPY_AND_ASSIGN(StartHandlerAtCrashTest); + StartHandlerForSelfTestOptions options_; + + DISALLOW_COPY_AND_ASSIGN(StartHandlerForSelfInChildTest); }; -TEST(CrashpadClient, StartHandlerAtCrash) { - StartHandlerAtCrashTest test; +TEST_P(StartHandlerForSelfTest, StartHandlerInChild) { + if (Options().set_first_chance_handler && !Options().simulate_crash) { + // TODO(jperaza): test first chance handlers with real crashes. + return; + } + StartHandlerForSelfInChildTest test(Options()); test.Run(); } +INSTANTIATE_TEST_SUITE_P(StartHandlerForSelfTestSuite, + StartHandlerForSelfTest, + testing::Combine(testing::Bool(), + testing::Bool(), + testing::Bool())); + // Test state for starting the handler for another process. class StartHandlerForClientTest { public: diff --git a/handler/crashpad_handler.md b/handler/crashpad_handler.md index 003ee2ef..c4126b62 100644 --- a/handler/crashpad_handler.md +++ b/handler/crashpad_handler.md @@ -121,13 +121,6 @@ establish the Crashpad client environment before running a program. Either this option or **--mach-service**, but not both, is required. This option is only valid on macOS. - * **--no-identify-client-via-url** - - Do not add client-identifying fields to the URL. By default, `"prod"`, - `"ver"`, and `"guid"` annotations are added to the upload URL as name-value - pairs `"product"`, `"version"`, and `"guid"`, respectively. Using this - option disables that behavior. - * **--initial-client-data**=*HANDLE_request_crash_dump*,*HANDLE_request_non_crash_dump*,*HANDLE_non_crash_dump_completed*,*HANDLE_first_pipe_instance*,*HANDLE_client_process*,*Address_crash_exception_information*,*Address_non_crash_exception_information*,*Address_debug_critical_section* Register the initial client using the inherited handles and data provided. @@ -141,6 +134,13 @@ establish the Crashpad client environment before running a program. client to register, and exits when all clients have exited, after waiting for any uploads in progress to complete. + * **--initial-client-fd**=_FD_ + + Wait for client requests on _FD_. Either this option or + **--trace-parent-with-exception**, but not both, is required. The handler + exits when all client connections have been closed. This option is only valid + on Linux platforms. + * **--mach-service**=_SERVICE_ Check in with the bootstrap server under the name _SERVICE_. Either this @@ -198,6 +198,13 @@ establish the Crashpad client environment before running a program. To prevent excessive accumulation of handler processes, _ARGUMENT_ must not be `--monitor-self`. +* **--no-identify-client-via-url** + + Do not add client-identifying fields to the URL. By default, `"prod"`, + `"ver"`, and `"guid"` annotations are added to the upload URL as name-value + pairs `"product"`, `"version"`, and `"guid"`, respectively. Using this + option disables that behavior. + * **--no-periodic-tasks** Do not scan for new pending crash reports or prune the crash report database. @@ -245,17 +252,24 @@ establish the Crashpad client environment before running a program. parent process. This option is only valid on macOS. Use of this option is discouraged. It should not be used absent extraordinary circumstances. + * **--sanitization-information**=_SANITIZATION-INFORMATION-ADDRESS_ + + Provides sanitization settings in a SanitizationInformation struct at + _SANITIZATION-INFORMATION-ADDRESS_. This option requires + **--trace-parent-with-exception** and is only valid on Linux platforms. + + * **--shared-client-connection** + + Indicates that the file descriptor provided by **--initial-client-fd** is + shared among mulitple clients. Using a broker process is not supported for + clients using this option. This option is only valid on Linux platforms. + * **--trace-parent-with-exception**=_EXCEPTION-INFORMATION-ADDRESS_ Causes the handler process to trace its parent process and exit. The parent process should have an ExceptionInformation struct at - _EXCEPTION-INFORMATION-ADDRESS_. - - * **--initial-client-fd**=_FD_ - - Starts the excetion handler server with an initial ExceptionHandlerClient - connected on the socket _FD_. The server will exit when all connected client - sockets have been closed. + _EXCEPTION-INFORMATION-ADDRESS_. This option is only valid on Linux + platforms. * **--url**=_URL_ diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 7820a89d..724168ee 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -118,6 +118,9 @@ void Usage(const base::FilePath& me) { " Address_debug_critical_section\n" " use precreated data to register initial client\n" #endif // OS_WIN +#if defined(OS_ANDROID) || defined(OS_LINUX) +" --initial-client-fd=FD a socket connected to a client.\n" +#endif // OS_ANDROID || OS_LINUX #if defined(OS_MACOSX) " --mach-service=SERVICE register SERVICE with the bootstrap server\n" #endif // OS_MACOSX @@ -141,11 +144,13 @@ void Usage(const base::FilePath& me) { " reset the server's exception handler to default\n" #endif // OS_MACOSX #if defined(OS_LINUX) || defined(OS_ANDROID) +" --sanitization-information=SANITIZATION_INFORMATION_ADDRESS\n" +" the address of a SanitizationInformation struct.\n" +" --shared-client-connection the file descriptor provided by\n" +" --initial-client-fd is shared among multiple\n" +" clients\n" " --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n" " request a dump for the handler's parent process\n" -" --initial-client-fd=FD a socket connected to a client.\n" -" --sanitization_information=SANITIZATION_INFORMATION_ADDRESS\n" -" the address of a SanitizationInformation struct.\n" #endif // OS_LINUX || OS_ANDROID " --url=URL send crash reports to this Breakpad server URL,\n" " only if uploads are enabled for the database\n" @@ -168,8 +173,9 @@ struct Options { bool reset_own_crash_exception_port_to_system_default; #elif defined(OS_LINUX) || defined(OS_ANDROID) VMAddress exception_information_address; - int initial_client_fd; VMAddress sanitization_information_address; + int initial_client_fd; + bool shared_client_connection; #elif defined(OS_WIN) std::string pipe_name; InitialClientData initial_client_data; @@ -530,6 +536,9 @@ int HandlerMain(int argc, #if defined(OS_WIN) kOptionInitialClientData, #endif // OS_WIN +#if defined(OS_ANDROID) || defined(OS_LINUX) + kOptionInitialClientFD, +#endif // OS_ANDROID || OS_LINUX #if defined(OS_MACOSX) kOptionMachService, #endif // OS_MACOSX @@ -548,9 +557,9 @@ int HandlerMain(int argc, kOptionResetOwnCrashExceptionPortToSystemDefault, #endif // OS_MACOSX #if defined(OS_LINUX) || defined(OS_ANDROID) - kOptionTraceParentWithException, - kOptionInitialClientFD, kOptionSanitizationInformation, + kOptionSharedClientConnection, + kOptionTraceParentWithException, #endif kOptionURL, @@ -571,6 +580,9 @@ int HandlerMain(int argc, nullptr, kOptionInitialClientData}, #endif // OS_MACOSX +#if defined(OS_ANDROID) || defined(OS_LINUX) + {"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD}, +#endif // OS_ANDROID || OS_LINUX #if defined(OS_MACOSX) {"mach-service", required_argument, nullptr, kOptionMachService}, #endif // OS_MACOSX @@ -601,15 +613,18 @@ int HandlerMain(int argc, kOptionResetOwnCrashExceptionPortToSystemDefault}, #endif // OS_MACOSX #if defined(OS_LINUX) || defined(OS_ANDROID) - {"trace-parent-with-exception", - required_argument, - nullptr, - kOptionTraceParentWithException}, - {"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD}, {"sanitization-information", required_argument, nullptr, kOptionSanitizationInformation}, + {"shared-client-connection", + no_argument, + nullptr, + kOptionSharedClientConnection}, + {"trace-parent-with-exception", + required_argument, + nullptr, + kOptionTraceParentWithException}, #endif // OS_LINUX || OS_ANDROID {"url", required_argument, nullptr, kOptionURL}, {"help", no_argument, nullptr, kOptionHelp}, @@ -622,14 +637,12 @@ int HandlerMain(int argc, options.handshake_fd = -1; #endif options.identify_client_via_url = true; +#if defined(OS_LINUX) || defined(OS_ANDROID) + options.initial_client_fd = kInvalidFileHandle; +#endif options.periodic_tasks = true; options.rate_limit = true; options.upload_gzip = true; -#if defined(OS_LINUX) || defined(OS_ANDROID) - options.exception_information_address = 0; - options.initial_client_fd = kInvalidFileHandle; - options.sanitization_information_address = 0; -#endif int opt; while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) { @@ -670,6 +683,15 @@ int HandlerMain(int argc, break; } #endif // OS_WIN +#if defined(OS_ANDROID) || defined(OS_LINUX) + case kOptionInitialClientFD: { + if (!base::StringToInt(optarg, &options.initial_client_fd)) { + ToolSupport::UsageHint(me, "failed to parse --initial-client-fd"); + return ExitFailure(); + } + break; + } +#endif // OS_ANDROID || OS_LINUX case kOptionMetrics: { options.metrics_dir = base::FilePath( ToolSupport::CommandLineArgumentToFilePathStringType(optarg)); @@ -720,21 +742,6 @@ int HandlerMain(int argc, } #endif // OS_MACOSX #if defined(OS_LINUX) || defined(OS_ANDROID) - case kOptionTraceParentWithException: { - if (!StringToNumber(optarg, &options.exception_information_address)) { - ToolSupport::UsageHint( - me, "failed to parse --trace-parent-with-exception"); - return ExitFailure(); - } - break; - } - case kOptionInitialClientFD: { - if (!base::StringToInt(optarg, &options.initial_client_fd)) { - ToolSupport::UsageHint(me, "failed to parse --initial-client-fd"); - return ExitFailure(); - } - break; - } case kOptionSanitizationInformation: { if (!StringToNumber(optarg, &options.sanitization_information_address)) { @@ -744,6 +751,18 @@ int HandlerMain(int argc, } break; } + case kOptionSharedClientConnection: { + options.shared_client_connection = true; + break; + } + case kOptionTraceParentWithException: { + if (!StringToNumber(optarg, &options.exception_information_address)) { + ToolSupport::UsageHint( + me, "failed to parse --trace-parent-with-exception"); + return ExitFailure(); + } + break; + } #endif // OS_LINUX || OS_ANDROID case kOptionURL: { options.url = optarg; @@ -793,7 +812,7 @@ int HandlerMain(int argc, if (!options.exception_information_address && options.initial_client_fd == kInvalidFileHandle) { ToolSupport::UsageHint( - me, "--trace-parent-with-exception or --initial_client_fd is required"); + me, "--trace-parent-with-exception or --initial-client-fd is required"); return ExitFailure(); } if (options.sanitization_information_address && @@ -803,6 +822,12 @@ int HandlerMain(int argc, "--sanitization_information requires --trace-parent-with-exception"); return ExitFailure(); } + if (options.shared_client_connection && + options.initial_client_fd == kInvalidFileHandle) { + ToolSupport::UsageHint( + me, "--shared-client-connection requires --initial-client-fd"); + return ExitFailure(); + } #endif // OS_MACOSX if (options.database.empty()) { @@ -994,7 +1019,8 @@ int HandlerMain(int argc, #elif defined(OS_LINUX) || defined(OS_ANDROID) if (options.initial_client_fd == kInvalidFileHandle || !exception_handler_server.InitializeWithClient( - ScopedFileHandle(options.initial_client_fd), false)) { + ScopedFileHandle(options.initial_client_fd), + options.shared_client_connection)) { return ExitFailure(); } #endif // OS_WIN From 18aa41d48ced1072147af6391a9706681824f008 Mon Sep 17 00:00:00 2001 From: Jonathan Metzman <metzman@chromium.org> Date: Mon, 6 May 2019 12:01:34 -0700 Subject: [PATCH 191/401] [libFuzzer] Enable fuzz targets to build in Chromium Enable building elf_image_reader_fuzzer in Chromium. Rename it to crashpad_elf_image_reader_fuzzer so that its clearer where the fuzzer comes from. Import chromium's fuzzer_test definition when building in Chromium and make sure fuzzer is only built on Linux since it breaks fuzzer build on Win (and maybe Mac?). Bug: 950093 Change-Id: I8afc104d26871311b04931b82a1600614a81bfc8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1597091 Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- build/crashpad_fuzzer_test.gni | 14 +++++++++++++- snapshot/BUILD.gn | 19 +++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/build/crashpad_fuzzer_test.gni b/build/crashpad_fuzzer_test.gni index 8e0eaa9f..ef4b0d82 100644 --- a/build/crashpad_fuzzer_test.gni +++ b/build/crashpad_fuzzer_test.gni @@ -14,8 +14,11 @@ import("crashpad_buildconfig.gni") import("test.gni") +if (crashpad_is_in_chromium) { + import("//testing/libfuzzer/fuzzer_test.gni") +} -template("fuzzer_test") { +template("crashpad_fuzzer_test") { if (crashpad_is_standalone && crashpad_use_libfuzzer) { test(target_name) { forward_variables_from(invoker, @@ -38,6 +41,15 @@ template("fuzzer_test") { } cflags += [ "-fsanitize=fuzzer" ] } + if (defined(invoker.seed_corpus)) { + not_needed(invoker, [ "seed_corpus" ]) + } + } else if (crashpad_is_in_chromium) { + # Append "crashpad_" to the beginning of the fuzzer's name to make it easier + # in Chromium to recognize where fuzzer came from. + forward_variables_from(invoker, "*") + fuzzer_test("crashpad_" + target_name) { + } } else { not_needed(invoker, "*") group(target_name) { diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 17488a08..4669062d 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -243,15 +243,18 @@ static_library("snapshot") { } } -fuzzer_test("elf_image_reader_fuzzer") { - sources = [ - "elf/elf_image_reader_fuzzer.cc", - ] +if (crashpad_is_linux) { + crashpad_fuzzer_test("elf_image_reader_fuzzer") { + sources = [ + "elf/elf_image_reader_fuzzer.cc", + ] - deps = [ - ":snapshot", - "../third_party/mini_chromium:base", - ] + deps = [ + ":snapshot", + "../third_party/mini_chromium:base", + ] + seed_corpus = "elf/elf_image_reader_fuzzer_corpus" + } } static_library("test_support") { From 856d40e220c977a4a07fbfa18c969afa8055b092 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Mon, 6 May 2019 15:15:06 -0700 Subject: [PATCH 192/401] Roll gtest to 3f5b5b8f This should fix the Fuchsia build due to an SDK API change that affected googletest. Change-Id: I9d72c11d660f053a96d326de4e1763ec7b85c7a4 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1597729 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 7f08b885..3feafd86 100644 --- a/DEPS +++ b/DEPS @@ -24,7 +24,7 @@ deps = { '3e50219fc4503f461b2176a9976891b28d80f9ab', 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + - '8b6d3f9c4a774bef3081195d422993323b6bb2e0', + '3f5b5b8f8493a03fa25f1e4a7eae7678514a431d', 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + '8bee09f4a57807136593ddc906b0b213c21f9014', From 02a3bf6e27128dfba46607021a8a43edd8986aff Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Tue, 7 May 2019 09:49:30 -0700 Subject: [PATCH 193/401] fuchsia: Tidy up return ZX_TASK_RETCODE_EXCEPTION_KILL after soft transition Bug: fuchsia:ZX-3473 Change-Id: Iad57d46e6eaffea96f276ce0e73ea87e812b488c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1599728 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- test/multiprocess_exec_fuchsia.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/multiprocess_exec_fuchsia.cc b/test/multiprocess_exec_fuchsia.cc index eff522b0..f91b3edc 100644 --- a/test/multiprocess_exec_fuchsia.cc +++ b/test/multiprocess_exec_fuchsia.cc @@ -95,14 +95,7 @@ void Multiprocess::SetExpectedChildTermination(TerminationReason reason, } void Multiprocess::SetExpectedChildTerminationBuiltinTrap() { - // TODO(scottmg): Once - // https://fuchsia-review.googlesource.com/c/fuchsia/+/256771 lands, remove - // this #ifdef, and always use ZX_TASK_RETCODE_EXCEPTION_KILL. -#if defined(ZX_TASK_RETCODE_EXCEPTION_KILL) constexpr ReturnCodeType kExpectedReturnCode = ZX_TASK_RETCODE_EXCEPTION_KILL; -#else - constexpr ReturnCodeType kExpectedReturnCode = -1; -#endif SetExpectedChildTermination(kTerminationNormal, kExpectedReturnCode); } From d221b7cadab5f00c6999f060a5bcb0896e25c7b7 Mon Sep 17 00:00:00 2001 From: David Pursell <dpursell@chromium.org> Date: Mon, 6 May 2019 15:18:50 -0700 Subject: [PATCH 194/401] [fuchsia] add a non-resuming exception API While switching over to the new channel-based exception APIs, we decided it probably no longer makes sense for crashpad to resume from exception itself, but instead let the caller do it. The first step is adding these new non-resuming APIs, and once callers have been switched over we will remove the existing port-based APIs. Bug: fuchsia:ZX-4031 Test: runtests Change-Id: I79a833479f4e5e57bce4baebc61e1b3f9faf70a4 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1597730 Reviewed-by: Scott Graham <scottmg@chromium.org> Reviewed-by: Francois Rousseau <frousseau@google.com> Commit-Queue: Francois Rousseau <frousseau@google.com> --- .../fuchsia/crash_report_exception_handler.cc | 13 ++++++++----- .../fuchsia/crash_report_exception_handler.h | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index b181cb60..34bed289 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -99,12 +99,15 @@ bool CrashReportExceptionHandler::HandleExceptionHandles( const zx::thread& thread, const zx::unowned_port& exception_port, UUID* local_report_id) { - ScopedTaskSuspend suspend(process); - - // Now that the thread has been successfully retrieved, it is possible to - // correctly call zx_task_resume_from_exception() to continue exception - // processing, even if something else during this function fails. ScopedThreadResumeAfterException resume(thread, exception_port); + return HandleException(process, thread, local_report_id); +} + +bool CrashReportExceptionHandler::HandleException( + const zx::process& process, + const zx::thread& thread, + UUID* local_report_id) { + ScopedTaskSuspend suspend(process); ProcessSnapshotFuchsia process_snapshot; if (!process_snapshot.Initialize(process)) { diff --git a/handler/fuchsia/crash_report_exception_handler.h b/handler/fuchsia/crash_report_exception_handler.h index c636fcae..57afe7d0 100644 --- a/handler/fuchsia/crash_report_exception_handler.h +++ b/handler/fuchsia/crash_report_exception_handler.h @@ -84,6 +84,8 @@ class CrashReportExceptionHandler { //! \param[out] local_report_id The unique identifier for the report created //! in the local report database. Optional. //! \return `true` on success, or `false` with an error logged. + //! + //! \deprecated Use the port-less version instead and have the caller resume. bool HandleException(uint64_t process_id, uint64_t thread_id, const zx::unowned_port& exception_port, @@ -104,11 +106,27 @@ class CrashReportExceptionHandler { //! \param[out] local_report_id The unique identifier for the report created //! in the local report database. Optional. //! \return `true` on success, or `false` with an error logged. + //! + //! \deprecated Use the port-less #HandleException instead. bool HandleExceptionHandles(const zx::process& process, const zx::thread& thread, const zx::unowned_port& exception_port, UUID* local_report_id = nullptr); + //! \brief Called when the exception handler server has caught an exception + //! and wants a crash dump to be taken. + //! + //! \param[in] process The handle to the process which sustained the + //! exception. + //! \param[in] thread The handle to the thread of \a process which sustained + //! the exception. + //! \param[out] local_report_id The unique identifier for the report created + //! in the local report database. Optional. + //! \return `true` on success, or `false` with an error logged. + bool HandleException(const zx::process& process, + const zx::thread& thread, + UUID* local_report_id = nullptr); + private: CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak From 949a022939aa90eabf1912a3b1851997e22535b9 Mon Sep 17 00:00:00 2001 From: Adam Kallai <kadam@inf.u-szeged.hu> Date: Thu, 16 May 2019 16:30:07 +0200 Subject: [PATCH 195/401] win: Fix 64-bit detection in ProcessInfo The ProcessInfo initialization fails on ARM on Windows with 'ReadProcessData failed'. The 64-bit detection logic only checks whether it's on x64 and ignores ARM64. On ARM64, the ReadProcessData template should be instantiated with internal::Traits64 as it is on x64. Test: Run crashpad_tests on ARM, 'ReadProcessData failed' is gone Change-Id: I0f47d8601a39aaa1b8ba07d34d1f41b7739233e7 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1615024 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/win/process_info.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/util/win/process_info.cc b/util/win/process_info.cc index fc0598ed..49a6f27f 100644 --- a/util/win/process_info.cc +++ b/util/win/process_info.cc @@ -513,8 +513,14 @@ bool ProcessInfo::Initialize(HANDLE process) { // distinguish between these two cases. SYSTEM_INFO system_info; GetSystemInfo(&system_info); - is_64_bit_ = - system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64; + +#if defined(ARCH_CPU_X86_FAMILY) + constexpr uint16_t kNative64BitArchitecture = PROCESSOR_ARCHITECTURE_AMD64; +#elif defined(ARCH_CPU_ARM_FAMILY) + constexpr uint16_t kNative64BitArchitecture = PROCESSOR_ARCHITECTURE_ARM64; +#endif + + is_64_bit_ = system_info.wProcessorArchitecture == kNative64BitArchitecture; } #if defined(ARCH_CPU_32_BITS) From bc9104541f2d24f34121f17b89c1151d227a3afd Mon Sep 17 00:00:00 2001 From: Roland McGrath <mcgrathr@chromium.org> Date: Sat, 11 May 2019 15:07:27 -0700 Subject: [PATCH 196/401] [fidl] Convert from - to . names for //zircon/public/fidl This is part of a soft transition to replace fuchsia-foo-bar names with fuchsia.foo.bar names for the directory and GN target names for FIDL libraries defined in //zircon/system/fidl and accessed in legacy GN via //zircon/public/fidl. After the transition, the directory and GN target names will exactly match the FIDL library names everywhere. 1. Make //zircon/public/fidl/a.b.c alias //zircon/public/fidl/a-b-c 2. Convert all //zircon/public/fidl uses outside fuchsia.git & integrate 3. Convert all //zircon/public/fidl uses inside fuchsia.git 4. Remove transition hacks 5. Enforce naming conventions in GN templates This is step 2. Bug: ZX-3365 #comment //third_party/crashpad references converted Change-Id: Ief90c6f9fa1da51dea7dbbd5b58741cbb7e06891 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1608163 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Roland McGrath <mcgrathr@chromium.org> --- third_party/fuchsia/BUILD.gn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index f10ccd0d..bf001e36 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -17,8 +17,8 @@ import("../../build/crashpad_buildconfig.gni") if (crashpad_is_in_fuchsia) { group("fuchsia") { public_deps = [ - "//zircon/public/fidl/fuchsia-mem", - "//zircon/public/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c", + "//zircon/public/fidl/fuchsia.mem", + "//zircon/public/fidl/fuchsia.sysinfo:fuchsia.sysinfo_c", "//zircon/public/lib/fdio", "//zircon/public/lib/zx", ] From 5ea6551baeb4404f47ebf89e23cf2aedb716ed73 Mon Sep 17 00:00:00 2001 From: Adam Barth <abarth@google.com> Date: Tue, 21 May 2019 11:21:31 -0700 Subject: [PATCH 197/401] [fuchsia] Update to fdio_pipe_half2 fdio_pipe_half is being replaced with fdio_pipe_half2. Change-Id: I01294f01692b0a90c00815ad02b6c30e41edba07 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1623147 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Adam Barth <abarth@chromium.org> --- test/multiprocess_exec_fuchsia.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/multiprocess_exec_fuchsia.cc b/test/multiprocess_exec_fuchsia.cc index f91b3edc..2f675869 100644 --- a/test/multiprocess_exec_fuchsia.cc +++ b/test/multiprocess_exec_fuchsia.cc @@ -30,14 +30,12 @@ namespace test { namespace { void AddPipe(fdio_spawn_action_t* action, int target_fd, int* fd_out) { - zx_handle_t handle; - uint32_t id; - zx_status_t status = fdio_pipe_half(&handle, &id); - ZX_CHECK(status >= 0, status) << "fdio_pipe_half"; + zx_handle_t handle = ZX_HANDLE_INVALID; + zx_status_t status = fdio_pipe_half2(fd_out, &handle); + ZX_CHECK(status == ZX_OK, status) << "fdio_pipe_half2"; action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; - action->h.id = PA_HND(PA_HND_TYPE(id), target_fd); + action->h.id = PA_HND(PA_FD, target_fd); action->h.handle = handle; - *fd_out = status; } } // namespace From 7b0155760628923bad5321c896af1ab2965c6d2a Mon Sep 17 00:00:00 2001 From: Julie Hockett <juliehockett@google.com> Date: Tue, 21 May 2019 13:29:35 -0700 Subject: [PATCH 198/401] Remove non-source files Recent changes to GN require only buildable files to be included in sources. See crbug.com/gn/77 for additional details. Change-Id: Ie3012fa5ae68a0886819647435fecb1d9c3d7aea Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1623149 Reviewed-by: Robert Sesek <rsesek@chromium.org> Commit-Queue: Robert Sesek <rsesek@chromium.org> --- snapshot/BUILD.gn | 1 - 1 file changed, 1 deletion(-) diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 4669062d..4a3b3d12 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -353,7 +353,6 @@ source_set("snapshot_test") { "crashpad_types/image_annotation_reader_test.cc", "elf/elf_image_reader_test.cc", "elf/elf_image_reader_test_note.S", - "elf/test_exported_symbols.sym", ] } From 122363ccaea7b568b3ec8f1d2d6d8f47de0e1106 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 23 May 2019 09:59:10 -0700 Subject: [PATCH 199/401] Fix compile for Linux 32b fuzz target This code was previously not enabled, but was turned on recently. However, there's no CQ check for 32 bit code. Bug: chromium:966292 Change-Id: I4a3205d8517575e25d3e525f247ad45a906c3e25 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1627679 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- snapshot/elf/elf_image_reader_fuzzer.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snapshot/elf/elf_image_reader_fuzzer.cc b/snapshot/elf/elf_image_reader_fuzzer.cc index 73bded72..4b9fcb0b 100644 --- a/snapshot/elf/elf_image_reader_fuzzer.cc +++ b/snapshot/elf/elf_image_reader_fuzzer.cc @@ -31,7 +31,8 @@ class FakeProcessMemory : public ProcessMemory { VMAddress offset_in_data = address - fake_base_; if (offset_in_data > size_) return -1; - ssize_t read_size = std::min(size_ - offset_in_data, size); + size_t read_size = + std::min(static_cast<size_t>(size_ - offset_in_data), size); memcpy(buffer, &data_[offset_in_data], read_size); return read_size; } From daf9f5669eedec1c326dd07f623872c1c4cc01a5 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 24 May 2019 12:49:28 -0700 Subject: [PATCH 200/401] Fix unchecked allocation size of in fuzzer note reading This fixes a fuzzer-only bug, and modifies the note API so that it can no longer request infinitely sized notes. Bug: chromium:966303 Change-Id: I97b9ca6774d3101560caddf2f9b0a8d7ecf7c2e2 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1628675 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- snapshot/elf/elf_image_reader.cc | 23 +++++++++++++++++------ snapshot/elf/elf_image_reader.h | 14 ++++++-------- snapshot/elf/elf_image_reader_fuzzer.cc | 2 +- snapshot/elf/elf_image_reader_test.cc | 4 ++-- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/snapshot/elf/elf_image_reader.cc b/snapshot/elf/elf_image_reader.cc index ffe3f7b1..7c03a363 100644 --- a/snapshot/elf/elf_image_reader.cc +++ b/snapshot/elf/elf_image_reader.cc @@ -228,10 +228,19 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::NextNote( return Result::kError; } +namespace { + +// The maximum size the user can specify for maximum note size. Clamping this +// ensures that buffer allocations cannot be wildly large. It is not expected +// that a note would be larger than ~1k in normal usage. +constexpr size_t kMaxMaxNoteSize = 16384; + +} // namespace + ElfImageReader::NoteReader::NoteReader(const ElfImageReader* elf_reader, const ProcessMemoryRange* range, const ProgramHeaderTable* phdr_table, - ssize_t max_note_size, + size_t max_note_size, const std::string& name_filter, NoteType type_filter, bool use_filter) @@ -242,12 +251,14 @@ ElfImageReader::NoteReader::NoteReader(const ElfImageReader* elf_reader, phdr_table_(phdr_table), segment_range_(), phdr_index_(0), - max_note_size_(max_note_size), + max_note_size_(std::min(kMaxMaxNoteSize, max_note_size)), name_filter_(name_filter), type_filter_(type_filter), use_filter_(use_filter), is_valid_(true), - retry_(false) {} + retry_(false) { + DCHECK_LT(max_note_size, kMaxMaxNoteSize); +} template <typename NhdrType> ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( @@ -282,7 +293,7 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( std::min(PAD(current_address_ + note_size), segment_end_address_); #undef PAD - if (max_note_size_ >= 0 && note_size > static_cast<size_t>(max_note_size_)) { + if (note_size > max_note_size_) { current_address_ = end_of_note; retry_ = true; return Result::kError; @@ -790,7 +801,7 @@ bool ElfImageReader::GetNumberOfSymbolEntriesFromDtGnuHash( } std::unique_ptr<ElfImageReader::NoteReader> ElfImageReader::Notes( - ssize_t max_note_size) { + size_t max_note_size) { return std::make_unique<NoteReader>( this, &memory_, program_headers_.get(), max_note_size); } @@ -798,7 +809,7 @@ std::unique_ptr<ElfImageReader::NoteReader> ElfImageReader::Notes( std::unique_ptr<ElfImageReader::NoteReader> ElfImageReader::NotesWithNameAndType(const std::string& name, NoteReader::NoteType type, - ssize_t max_note_size) { + size_t max_note_size) { return std::make_unique<NoteReader>( this, &memory_, program_headers_.get(), max_note_size, name, type, true); } diff --git a/snapshot/elf/elf_image_reader.h b/snapshot/elf/elf_image_reader.h index f35c7616..ab1799f3 100644 --- a/snapshot/elf/elf_image_reader.h +++ b/snapshot/elf/elf_image_reader.h @@ -83,7 +83,7 @@ class ElfImageReader { NoteReader(const ElfImageReader* elf_reader_, const ProcessMemoryRange* range, const ProgramHeaderTable* phdr_table, - ssize_t max_note_size, + size_t max_note_size, const std::string& name_filter = std::string(), NoteType type_filter = 0, bool use_filter = false); @@ -105,7 +105,7 @@ class ElfImageReader { const ProgramHeaderTable* phdr_table_; // weak std::unique_ptr<ProcessMemoryRange> segment_range_; size_t phdr_index_; - ssize_t max_note_size_; + size_t max_note_size_; std::string name_filter_; NoteType type_filter_; bool use_filter_; @@ -211,10 +211,9 @@ class ElfImageReader { //! //! \param[in] max_note_size The maximum note size to read. Notes whose //! combined name, descriptor, and padding size are greater than - //! \a max_note_size will be silently skipped. A \a max_note_size of -1 - //! indicates infinite maximum note size. + //! \a max_note_size will be silently skipped. //! \return A NoteReader object capable of reading notes in this image. - std::unique_ptr<NoteReader> Notes(ssize_t max_note_size); + std::unique_ptr<NoteReader> Notes(size_t max_note_size); //! \brief Return a NoteReader for this image, which scans all PT_NOTE //! segments in the image, filtering by name and type. @@ -226,12 +225,11 @@ class ElfImageReader { //! \param[in] type The note type to match. //! \param[in] max_note_size The maximum note size to read. Notes whose //! combined name, descriptor, and padding size are greater than - //! \a max_note_size will be silently skipped. A \a max_note_size of -1 - //! indicates infinite maximum note size. + //! \a max_note_size will be silently skipped. //! \return A NoteReader object capable of reading notes in this image. std::unique_ptr<NoteReader> NotesWithNameAndType(const std::string& name, NoteReader::NoteType type, - ssize_t max_note_size); + size_t max_note_size); //! \brief Return a ProcessMemoryRange restricted to the range of this image. //! diff --git a/snapshot/elf/elf_image_reader_fuzzer.cc b/snapshot/elf/elf_image_reader_fuzzer.cc index 4b9fcb0b..b780af4e 100644 --- a/snapshot/elf/elf_image_reader_fuzzer.cc +++ b/snapshot/elf/elf_image_reader_fuzzer.cc @@ -67,7 +67,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { std::string note_desc; ElfImageReader::NoteReader::NoteType note_type; VMAddress desc_addr; - auto notes = reader.Notes(-1); + auto notes = reader.Notes(9999); while ((result = notes->NextNote( ¬e_name, ¬e_type, ¬e_desc, &desc_addr)) == ElfImageReader::NoteReader::Result::kSuccess) { diff --git a/snapshot/elf/elf_image_reader_test.cc b/snapshot/elf/elf_image_reader_test.cc index 971ed229..cf8f33b6 100644 --- a/snapshot/elf/elf_image_reader_test.cc +++ b/snapshot/elf/elf_image_reader_test.cc @@ -155,7 +155,7 @@ void ReadThisExecutableInTarget(ProcessType process, ElfImageReader::NoteReader::NoteType note_type; VMAddress desc_addr; - std::unique_ptr<ElfImageReader::NoteReader> notes = reader.Notes(-1); + std::unique_ptr<ElfImageReader::NoteReader> notes = reader.Notes(10000); while ((result = notes->NextNote( ¬e_name, ¬e_type, ¬e_desc, &desc_addr)) == ElfImageReader::NoteReader::Result::kSuccess) { @@ -169,7 +169,7 @@ void ReadThisExecutableInTarget(ProcessType process, // Find the note defined in elf_image_reader_test_note.S. constexpr uint32_t kCrashpadNoteDesc = 42; notes = reader.NotesWithNameAndType( - CRASHPAD_ELF_NOTE_NAME, CRASHPAD_ELF_NOTE_TYPE_SNAPSHOT_TEST, -1); + CRASHPAD_ELF_NOTE_NAME, CRASHPAD_ELF_NOTE_TYPE_SNAPSHOT_TEST, 10000); ASSERT_EQ(notes->NextNote(¬e_name, ¬e_type, ¬e_desc, &desc_addr), ElfImageReader::NoteReader::Result::kSuccess); EXPECT_EQ(note_name, CRASHPAD_ELF_NOTE_NAME); From ee1d5124a2bfec578a1474b048cf934d92dcf7ba Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Mon, 27 May 2019 10:26:15 -0700 Subject: [PATCH 201/401] Fix incorrect range checks in elf image note reader Overflows before and after padding could cause the max note size check to be evaded. Bug: chromium:967228, chromium: 967257, chromium:967223 Change-Id: I499a273e76e78529fc59ddcb74055be6d01fa2cb Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1631635 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- snapshot/elf/elf_image_reader.cc | 39 ++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/snapshot/elf/elf_image_reader.cc b/snapshot/elf/elf_image_reader.cc index 7c03a363..7f6d7c7e 100644 --- a/snapshot/elf/elf_image_reader.cc +++ b/snapshot/elf/elf_image_reader.cc @@ -22,6 +22,7 @@ #include <vector> #include "base/logging.h" +#include "base/numerics/safe_math.h" #include "build/build_config.h" #include "util/numeric/checked_vm_address_range.h" @@ -277,10 +278,24 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( current_address_ += sizeof(note_info); constexpr size_t align = sizeof(note_info.n_namesz); -#define PAD(x) (((x) + align - 1) & ~(align - 1)) - size_t padded_namesz = PAD(note_info.n_namesz); - size_t padded_descsz = PAD(note_info.n_descsz); - size_t note_size = padded_namesz + padded_descsz; + +#define CHECKED_PAD(x, into) \ + base::CheckAnd(base::CheckAdd(x, align - 1), ~(align - 1)) \ + .AssignIfValid(&into) + + size_t padded_namesz; + if (!CHECKED_PAD(note_info.n_namesz, padded_namesz)) { + return Result::kError; + } + size_t padded_descsz; + if (!CHECKED_PAD(note_info.n_descsz, padded_descsz)) { + return Result::kError; + } + + size_t note_size; + if (!base::CheckAdd(padded_namesz, padded_descsz).AssignIfValid(¬e_size)) { + return Result::kError; + } // Notes typically have 4-byte alignment. However, .note.android.ident may // inadvertently use 2-byte alignment. @@ -289,9 +304,19 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( // but there may be 4-byte aligned notes following it. If this note was // aligned at less than 4-bytes, expect that the next note will be aligned at // 4-bytes and add extra padding, if necessary. - VMAddress end_of_note = - std::min(PAD(current_address_ + note_size), segment_end_address_); -#undef PAD + + VMAddress end_of_note_candidate; + if (!base::CheckAdd(current_address_, note_size) + .AssignIfValid(&end_of_note_candidate)) { + return Result::kError; + } + VMAddress end_of_note; + if (!CHECKED_PAD(end_of_note_candidate, end_of_note)) { + return Result::kError; + } + end_of_note = std::min(end_of_note, segment_end_address_); + +#undef CHECKED_PAD if (note_size > max_note_size_) { current_address_ = end_of_note; From 3e5da31f900c9b1f2dfa9766fd7e051265900fb5 Mon Sep 17 00:00:00 2001 From: Julie Hockett <juliehockett@google.com> Date: Tue, 28 May 2019 11:01:26 -0700 Subject: [PATCH 202/401] Remove non-source files from library Recent changes to GN mean that non-source files in final targets are an error. Since they were ignored previously, this should be an NFC. See crbug.com/gn/77 for details. Change-Id: Ifc845a3b3b044e71ab4086ab19748adb7b4d4d08 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1632676 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- snapshot/BUILD.gn | 7 ------- 1 file changed, 7 deletions(-) diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 4a3b3d12..25805c23 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -95,16 +95,9 @@ static_library("snapshot") { "mac/process_snapshot_mac.h", "mac/process_types.cc", "mac/process_types.h", - "mac/process_types/all.proctype", - "mac/process_types/annotation.proctype", - "mac/process_types/crashpad_info.proctype", - "mac/process_types/crashreporterclient.proctype", "mac/process_types/custom.cc", - "mac/process_types/dyld_images.proctype", "mac/process_types/flavors.h", "mac/process_types/internal.h", - "mac/process_types/loader.proctype", - "mac/process_types/nlist.proctype", "mac/process_types/traits.h", "mac/system_snapshot_mac.cc", "mac/system_snapshot_mac.h", From c5f296c0447d54305c6492c0f9aeef3069b3689e Mon Sep 17 00:00:00 2001 From: Adam Kallai <kadam@inf.u-szeged.hu> Date: Mon, 3 Jun 2019 10:47:48 +0200 Subject: [PATCH 203/401] Disable CPUX86SupportsDAZ unit test on Windows ARM64 This unit test is related to X86 CPU Family, it could be disabled on ARM64. Bug: None Test: Run crashpad_tests, it's disabled on ARM64 Change-Id: I7ebe5dd7d8964e8efd0ebcd96944e5981f8b7606 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1634772 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- snapshot/win/system_snapshot_win_test.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snapshot/win/system_snapshot_win_test.cc b/snapshot/win/system_snapshot_win_test.cc index 80659930..a8ccd32b 100644 --- a/snapshot/win/system_snapshot_win_test.cc +++ b/snapshot/win/system_snapshot_win_test.cc @@ -79,11 +79,13 @@ TEST_F(SystemSnapshotWinTest, CPUVendor) { EXPECT_TRUE(cpu_vendor == "GenuineIntel" || cpu_vendor == "AuthenticAMD"); } +#if defined(ARCH_CPU_X86_FAMILY) TEST_F(SystemSnapshotWinTest, CPUX86SupportsDAZ) { // Most SSE2+ machines support Denormals-Are-Zero. This may fail if run on // older machines. EXPECT_TRUE(system_snapshot().CPUX86SupportsDAZ()); } +#endif TEST_F(SystemSnapshotWinTest, GetOperatingSystem) { EXPECT_EQ(system_snapshot().GetOperatingSystem(), From 76e761f7a6b90fdf70eaa2db59dc79c016a7cf8a Mon Sep 17 00:00:00 2001 From: Adam Barth <abarth@google.com> Date: Tue, 4 Jun 2019 08:51:18 -0700 Subject: [PATCH 204/401] [fuchsia] Switch to fdio_pipe_half fdio_pipe_half2 and fdio_pipe_half are now the same. We can complete the migration by switching back to the cleaner name. Change-Id: Ibf2ab290300e37adbb19df60f7b4869e8150ec5b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1643209 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Adam Barth <abarth@chromium.org> --- test/multiprocess_exec_fuchsia.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/multiprocess_exec_fuchsia.cc b/test/multiprocess_exec_fuchsia.cc index 2f675869..a1e2acf5 100644 --- a/test/multiprocess_exec_fuchsia.cc +++ b/test/multiprocess_exec_fuchsia.cc @@ -31,8 +31,8 @@ namespace { void AddPipe(fdio_spawn_action_t* action, int target_fd, int* fd_out) { zx_handle_t handle = ZX_HANDLE_INVALID; - zx_status_t status = fdio_pipe_half2(fd_out, &handle); - ZX_CHECK(status == ZX_OK, status) << "fdio_pipe_half2"; + zx_status_t status = fdio_pipe_half(fd_out, &handle); + ZX_CHECK(status == ZX_OK, status) << "fdio_pipe_half"; action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; action->h.id = PA_HND(PA_FD, target_fd); action->h.handle = handle; From 4920d248fedf05dd148b34002defa5d7175257b8 Mon Sep 17 00:00:00 2001 From: Fabrice de Gans-Riberi <fdegans@chromium.org> Date: Fri, 7 Jun 2019 10:47:33 -0700 Subject: [PATCH 205/401] Roll gtest to da10da05c262af0a9e8fa91789a272a3dec67655. This includes a change to the fdio_pipe_half() Fuchsia API that is necessary to deprecate the old version of the API. Bug: chromium:972118 Change-Id: If9e9de397064cd5cc5709e787e8ba3b02e7b1942 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1650142 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Fabrice de Gans-Riberi <fdegans@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 3feafd86..33310cd1 100644 --- a/DEPS +++ b/DEPS @@ -24,7 +24,7 @@ deps = { '3e50219fc4503f461b2176a9976891b28d80f9ab', 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + - '3f5b5b8f8493a03fa25f1e4a7eae7678514a431d', + 'da10da05c262af0a9e8fa91789a272a3dec67655', 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + '8bee09f4a57807136593ddc906b0b213c21f9014', From e0e83ad18af41dba0ae10e0204193ec9074aeb2a Mon Sep 17 00:00:00 2001 From: Erik Chen <erikchen@chromium.org> Date: Fri, 7 Jun 2019 11:37:56 -0700 Subject: [PATCH 206/401] Use explicit paths when using hermetic toolchain. Previously, both the invocation to mig and mig's internal code would use xcrun to locate binaries. When we're using the hermetic toolchain, we want to explicitly specify the binaries to use and we want to avoid calls to xcrun. Bug: chromium:971452 Change-Id: I8527368e0846bc72789e6454fcd626b028d297ff Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1650147 Commit-Queue: Erik Chen <erikchen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/BUILD.gn | 14 ++++++++++++-- util/mach/mig.py | 3 ++- util/mach/mig_gen.py | 22 +++++++++++++++------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index 620ae255..cfa4e225 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -47,9 +47,19 @@ if (crashpad_is_mac) { args += rebase_path(outputs, root_build_dir) if (crashpad_is_in_chromium) { if (!use_system_xcode) { + import("//build/config/clang/clang.gni") + import("//build/config/mac/mac_sdk.gni") + clang_path = rebase_path("$clang_base_path/bin/", root_build_dir) + "clang" + mig_path = "$mac_bin_path" + "mig" + migcom_path = "$mac_bin_path" + "../libexec/migcom" + args += [ - "--developer-dir", - hermetic_xcode_path, + "--clang-path", + clang_path, + "--mig-path", + mig_path, + "--migcom-path", + migcom_path, ] } } diff --git a/util/mach/mig.py b/util/mach/mig.py index c2357338..ef14031c 100755 --- a/util/mach/mig.py +++ b/util/mach/mig.py @@ -26,7 +26,8 @@ def main(args): interface = mig_gen.MigInterface(parsed.user_c, parsed.server_c, parsed.user_h, parsed.server_h) mig_gen.generate_interface(parsed.defs, interface, parsed.include, - parsed.developer_dir, parsed.sdk) + parsed.sdk, parsed.clang_path, parsed.mig_path, + parsed.migcom_path) mig_fix.fix_interface(interface) if __name__ == '__main__': diff --git a/util/mach/mig_gen.py b/util/mach/mig_gen.py index d71029a4..976cd126 100755 --- a/util/mach/mig_gen.py +++ b/util/mach/mig_gen.py @@ -24,16 +24,21 @@ import sys MigInterface = collections.namedtuple('MigInterface', ['user_c', 'server_c', 'user_h', 'server_h']) -def generate_interface(defs, interface, includes=[], - developer_dir=None, sdk=None): - command = ['mig', +def generate_interface(defs, interface, includes=[], sdk=None, clang_path=None, + mig_path=None, migcom_path=None): + if mig_path is None: + mig_path = 'mig' + command = [mig_path, '-user', interface.user_c, '-server', interface.server_c, '-header', interface.user_h, '-sheader', interface.server_h, ] - if developer_dir is not None: - os.environ['DEVELOPER_DIR'] = developer_dir + + if clang_path is not None: + os.environ['MIGCC'] = clang_path + if migcom_path is not None: + os.environ['MIGCOM'] = migcom_path if sdk is not None: command.extend(['-isysroot', sdk]) for include in includes: @@ -43,7 +48,9 @@ def generate_interface(defs, interface, includes=[], def parse_args(args): parser = argparse.ArgumentParser() - parser.add_argument('--developer-dir', help='Path to Xcode') + parser.add_argument('--clang-path', help='Path to Clang') + parser.add_argument('--mig-path', help='Path to mig') + parser.add_argument('--migcom-path', help='Path to migcom') parser.add_argument('--sdk', help='Path to SDK') parser.add_argument('--include', default=[], @@ -61,7 +68,8 @@ def main(args): interface = MigInterface(parsed.user_c, parsed.server_c, parsed.user_h, parsed.server_h) generate_interface(parsed.defs, interface, parsed.include, - parsed.developer_dir, parsed.sdk) + parsed.sdk, parsed.clang_path, parsed.mig_path, + parsed.migcom_path) if __name__ == '__main__': sys.exit(main(sys.argv[1:])) From d85f898a696a5b44042a7772690352f7e89ad591 Mon Sep 17 00:00:00 2001 From: Clark DuVall <cduvall@chromium.org> Date: Mon, 10 Jun 2019 12:15:46 -0700 Subject: [PATCH 207/401] Refactor MemorySnapshotGeneric to use ProcessMemory instead of ProcessReader Also remove MemorySnapshotWin since the code is identical to MemorySnapshotGeneric now. Bug: crashpad:95 Change-Id: I9a631f8eb206dd72a69158021db87e8db41c5913 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1642148 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Commit-Queue: Clark DuVall <cduvall@chromium.org> --- snapshot/BUILD.gn | 2 - snapshot/fuchsia/thread_snapshot_fuchsia.cc | 4 +- snapshot/fuchsia/thread_snapshot_fuchsia.h | 2 +- snapshot/linux/thread_snapshot_linux.cc | 5 +- snapshot/linux/thread_snapshot_linux.h | 2 +- snapshot/mac/thread_snapshot_mac.cc | 2 +- snapshot/mac/thread_snapshot_mac.h | 2 +- snapshot/memory_snapshot.h | 25 ------- snapshot/memory_snapshot_generic.h | 36 ++++++---- snapshot/snapshot.gyp | 2 - snapshot/win/capture_memory_delegate_win.cc | 10 +-- snapshot/win/capture_memory_delegate_win.h | 10 +-- snapshot/win/exception_snapshot_win.cc | 4 +- snapshot/win/exception_snapshot_win.h | 4 +- snapshot/win/memory_snapshot_win.cc | 75 --------------------- snapshot/win/memory_snapshot_win.h | 75 --------------------- snapshot/win/module_snapshot_win.cc | 8 +-- snapshot/win/process_snapshot_win.cc | 12 ++-- snapshot/win/process_snapshot_win.h | 12 ++-- snapshot/win/thread_snapshot_win.cc | 9 +-- snapshot/win/thread_snapshot_win.h | 8 +-- 21 files changed, 72 insertions(+), 237 deletions(-) delete mode 100644 snapshot/win/memory_snapshot_win.cc delete mode 100644 snapshot/win/memory_snapshot_win.h diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 25805c23..ae5b9cef 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -170,8 +170,6 @@ static_library("snapshot") { "win/exception_snapshot_win.h", "win/memory_map_region_snapshot_win.cc", "win/memory_map_region_snapshot_win.h", - "win/memory_snapshot_win.cc", - "win/memory_snapshot_win.h", "win/module_snapshot_win.cc", "win/module_snapshot_win.h", "win/pe_image_annotations_reader.cc", diff --git a/snapshot/fuchsia/thread_snapshot_fuchsia.cc b/snapshot/fuchsia/thread_snapshot_fuchsia.cc index b3a4cec1..462cdb1f 100644 --- a/snapshot/fuchsia/thread_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/thread_snapshot_fuchsia.cc @@ -52,9 +52,9 @@ bool ThreadSnapshotFuchsia::Initialize( #endif if (thread.stack_regions.empty()) { - stack_.Initialize(process_reader, 0, 0); + stack_.Initialize(process_reader->Memory(), 0, 0); } else { - stack_.Initialize(process_reader, + stack_.Initialize(process_reader->Memory(), thread.stack_regions[0].base(), thread.stack_regions[0].size()); // TODO(scottmg): Handle split stack by adding other parts to ExtraMemory(). diff --git a/snapshot/fuchsia/thread_snapshot_fuchsia.h b/snapshot/fuchsia/thread_snapshot_fuchsia.h index db975976..45d4f117 100644 --- a/snapshot/fuchsia/thread_snapshot_fuchsia.h +++ b/snapshot/fuchsia/thread_snapshot_fuchsia.h @@ -67,7 +67,7 @@ class ThreadSnapshotFuchsia final : public ThreadSnapshot { #error Port. #endif CPUContext context_; - MemorySnapshotGeneric<ProcessReaderFuchsia> stack_; + MemorySnapshotGeneric stack_; zx_koid_t thread_id_; zx_vaddr_t thread_specific_data_address_; InitializationStateDcheck initialized_; diff --git a/snapshot/linux/thread_snapshot_linux.cc b/snapshot/linux/thread_snapshot_linux.cc index f40c78e8..e3e2bebd 100644 --- a/snapshot/linux/thread_snapshot_linux.cc +++ b/snapshot/linux/thread_snapshot_linux.cc @@ -190,8 +190,9 @@ bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader, #error Port. #endif - stack_.Initialize( - process_reader, thread.stack_region_address, thread.stack_region_size); + stack_.Initialize(process_reader->Memory(), + thread.stack_region_address, + thread.stack_region_size); thread_specific_data_address_ = thread.thread_info.thread_specific_data_address; diff --git a/snapshot/linux/thread_snapshot_linux.h b/snapshot/linux/thread_snapshot_linux.h index 17e471f3..44cc6f6d 100644 --- a/snapshot/linux/thread_snapshot_linux.h +++ b/snapshot/linux/thread_snapshot_linux.h @@ -73,7 +73,7 @@ class ThreadSnapshotLinux final : public ThreadSnapshot { #endif // ARCH_CPU_X86_FAMILY } context_union_; CPUContext context_; - MemorySnapshotGeneric<ProcessReaderLinux> stack_; + MemorySnapshotGeneric stack_; LinuxVMAddress thread_specific_data_address_; pid_t thread_id_; int priority_; diff --git a/snapshot/mac/thread_snapshot_mac.cc b/snapshot/mac/thread_snapshot_mac.cc index f45fc418..8fbb3e70 100644 --- a/snapshot/mac/thread_snapshot_mac.cc +++ b/snapshot/mac/thread_snapshot_mac.cc @@ -49,7 +49,7 @@ bool ThreadSnapshotMac::Initialize( thread_specific_data_address_ = process_reader_thread.thread_specific_data_address; - stack_.Initialize(process_reader, + stack_.Initialize(process_reader->Memory(), process_reader_thread.stack_region_address, process_reader_thread.stack_region_size); diff --git a/snapshot/mac/thread_snapshot_mac.h b/snapshot/mac/thread_snapshot_mac.h index 8f5d722b..946b0085 100644 --- a/snapshot/mac/thread_snapshot_mac.h +++ b/snapshot/mac/thread_snapshot_mac.h @@ -70,7 +70,7 @@ class ThreadSnapshotMac final : public ThreadSnapshot { } context_union_; #endif CPUContext context_; - MemorySnapshotGeneric<ProcessReaderMac> stack_; + MemorySnapshotGeneric stack_; uint64_t thread_id_; uint64_t thread_specific_data_address_; thread_t thread_; diff --git a/snapshot/memory_snapshot.h b/snapshot/memory_snapshot.h index 9e274a0e..5dbac5ad 100644 --- a/snapshot/memory_snapshot.h +++ b/snapshot/memory_snapshot.h @@ -111,31 +111,6 @@ bool DetermineMergedRange(const MemorySnapshot* a, const MemorySnapshot* b, CheckedRange<uint64_t, size_t>* merged); -namespace internal { - -//! \brief A standard implementation of MemorySnapshot::MergeWithOtherSnapshot() -//! for concrete MemorySnapshot implementations that use a -//! `process_reader_`. -template <class T> -const MemorySnapshot* MergeWithOtherSnapshotImpl(const T* self, - const MemorySnapshot* other) { - const T* other_as_memory_snapshot_concrete = - reinterpret_cast<const T*>(other); - if (self->process_reader_ != - other_as_memory_snapshot_concrete->process_reader_) { - LOG(ERROR) << "different process_reader_ for snapshots"; - return nullptr; - } - CheckedRange<uint64_t, size_t> merged(0, 0); - if (!LoggingDetermineMergedRange(self, other, &merged)) - return nullptr; - - std::unique_ptr<T> result(new T()); - result->Initialize(self->process_reader_, merged.base(), merged.size()); - return result.release(); -} - -} // namespace internal } // namespace crashpad #endif // CRASHPAD_SNAPSHOT_MEMORY_SNAPSHOT_H_ diff --git a/snapshot/memory_snapshot_generic.h b/snapshot/memory_snapshot_generic.h index 402e913e..1a74d4e4 100644 --- a/snapshot/memory_snapshot_generic.h +++ b/snapshot/memory_snapshot_generic.h @@ -19,6 +19,7 @@ #include <sys/types.h> #include "base/macros.h" +#include "base/numerics/safe_math.h" #include "snapshot/memory_snapshot.h" #include "util/misc/address_types.h" #include "util/misc/initialization_state_dcheck.h" @@ -30,7 +31,6 @@ namespace internal { //! \brief A MemorySnapshot of a memory region in a process on the running //! system. Used on Mac, Linux, Android, and Fuchsia, templated on the //! platform-specific ProcessReader type. -template <class ProcessReaderType> class MemorySnapshotGeneric final : public MemorySnapshot { public: MemorySnapshotGeneric() = default; @@ -42,25 +42,25 @@ class MemorySnapshotGeneric final : public MemorySnapshot { //! until Read() is called, and the memory snapshot data is discared when //! Read() returns. //! - //! \param[in] process_reader A reader for the process being snapshotted. + //! \param[in] process_memory A reader for the process being snapshotted. //! \param[in] address The base address of the memory region to snapshot, in //! the snapshot process’ address space. //! \param[in] size The size of the memory region to snapshot. - void Initialize(ProcessReaderType* process_reader, + void Initialize(const ProcessMemory* process_memory, VMAddress address, VMSize size) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); - process_reader_ = process_reader; + process_memory_ = process_memory; address_ = address; - size_ = size; + size_ = base::checked_cast<size_t>(size); INITIALIZATION_STATE_SET_VALID(initialized_); } // MemorySnapshot: uint64_t Address() const override { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return address_; + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return address_; } size_t Size() const override { @@ -76,7 +76,7 @@ class MemorySnapshotGeneric final : public MemorySnapshot { } std::unique_ptr<uint8_t[]> buffer(new uint8_t[size_]); - if (!process_reader_->Memory()->Read(address_, size_, buffer.get())) { + if (!process_memory_->Read(address_, size_, buffer.get())) { return false; } return delegate->MemorySnapshotDelegateRead(buffer.get(), size_); @@ -84,7 +84,19 @@ class MemorySnapshotGeneric final : public MemorySnapshot { const MemorySnapshot* MergeWithOtherSnapshot( const MemorySnapshot* other) const override { - return MergeWithOtherSnapshotImpl(this, other); + const MemorySnapshotGeneric* other_as_memory_snapshot_concrete = + reinterpret_cast<const MemorySnapshotGeneric*>(other); + if (process_memory_ != other_as_memory_snapshot_concrete->process_memory_) { + LOG(ERROR) << "different process_memory_ for snapshots"; + return nullptr; + } + CheckedRange<uint64_t, size_t> merged(0, 0); + if (!LoggingDetermineMergedRange(this, other, &merged)) + return nullptr; + + auto result = std::make_unique<MemorySnapshotGeneric>(); + result->Initialize(process_memory_, merged.base(), merged.size()); + return result.release(); } private: @@ -93,9 +105,9 @@ class MemorySnapshotGeneric final : public MemorySnapshot { const T* self, const MemorySnapshot* other); - ProcessReaderType* process_reader_; // weak - uint64_t address_; - uint64_t size_; + const ProcessMemory* process_memory_; // weak + VMAddress address_; + size_t size_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(MemorySnapshotGeneric); diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 0b4e157b..c4b7d52e 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -155,8 +155,6 @@ 'win/capture_memory_delegate_win.h', 'win/memory_map_region_snapshot_win.cc', 'win/memory_map_region_snapshot_win.h', - 'win/memory_snapshot_win.cc', - 'win/memory_snapshot_win.h', 'win/module_snapshot_win.cc', 'win/module_snapshot_win.h', 'win/pe_image_annotations_reader.cc', diff --git a/snapshot/win/capture_memory_delegate_win.cc b/snapshot/win/capture_memory_delegate_win.cc index b652f4a4..ee5e5d64 100644 --- a/snapshot/win/capture_memory_delegate_win.cc +++ b/snapshot/win/capture_memory_delegate_win.cc @@ -17,7 +17,7 @@ #include <utility> #include "base/numerics/safe_conversions.h" -#include "snapshot/win/memory_snapshot_win.h" +#include "snapshot/memory_snapshot_generic.h" namespace crashpad { namespace internal { @@ -25,7 +25,7 @@ namespace internal { CaptureMemoryDelegateWin::CaptureMemoryDelegateWin( ProcessReaderWin* process_reader, const ProcessReaderWin::Thread& thread, - std::vector<std::unique_ptr<MemorySnapshotWin>>* snapshots, + std::vector<std::unique_ptr<MemorySnapshotGeneric>>* snapshots, uint32_t* budget_remaining) : stack_(thread.stack_region_address, thread.stack_region_size), process_reader_(process_reader), @@ -57,9 +57,9 @@ void CaptureMemoryDelegateWin::AddNewMemorySnapshot( return; if (budget_remaining_ && *budget_remaining_ == 0) return; - snapshots_->push_back(std::make_unique<internal::MemorySnapshotWin>()); - internal::MemorySnapshotWin* snapshot = snapshots_->back().get(); - snapshot->Initialize(process_reader_, range.base(), range.size()); + snapshots_->push_back(std::make_unique<internal::MemorySnapshotGeneric>()); + internal::MemorySnapshotGeneric* snapshot = snapshots_->back().get(); + snapshot->Initialize(process_reader_->Memory(), range.base(), range.size()); if (budget_remaining_) { if (!base::IsValueInRangeForNumericType<int64_t>(range.size())) { *budget_remaining_ = 0; diff --git a/snapshot/win/capture_memory_delegate_win.h b/snapshot/win/capture_memory_delegate_win.h index 175b4c95..85c3db97 100644 --- a/snapshot/win/capture_memory_delegate_win.h +++ b/snapshot/win/capture_memory_delegate_win.h @@ -28,7 +28,7 @@ namespace crashpad { namespace internal { -class MemorySnapshotWin; +class MemorySnapshotGeneric; class CaptureMemoryDelegateWin : public CaptureMemory::Delegate { public: @@ -38,15 +38,15 @@ class CaptureMemoryDelegateWin : public CaptureMemory::Delegate { //! \param[in] thread The thread being inspected. Memory ranges overlapping //! this thread's stack will be ignored on the assumption that they're //! already captured elsewhere. - //! \param[in] snapshots A vector of MemorySnapshotWin to which the captured - //! memory will be added. + //! \param[in] snapshots A vector of MemorySnapshotGeneric to which the + //! captured memory will be added. //! \param[in] budget_remaining If non-null, a pointer to the remaining number //! of bytes to capture. If this is `0`, no further memory will be //! captured. CaptureMemoryDelegateWin( ProcessReaderWin* process_reader, const ProcessReaderWin::Thread& thread, - std::vector<std::unique_ptr<MemorySnapshotWin>>* snapshots, + std::vector<std::unique_ptr<MemorySnapshotGeneric>>* snapshots, uint32_t* budget_remaining); // MemoryCaptureDelegate: @@ -60,7 +60,7 @@ class CaptureMemoryDelegateWin : public CaptureMemory::Delegate { private: CheckedRange<uint64_t, uint64_t> stack_; ProcessReaderWin* process_reader_; // weak - std::vector<std::unique_ptr<MemorySnapshotWin>>* snapshots_; // weak + std::vector<std::unique_ptr<MemorySnapshotGeneric>>* snapshots_; // weak uint32_t* budget_remaining_; }; diff --git a/snapshot/win/exception_snapshot_win.cc b/snapshot/win/exception_snapshot_win.cc index e8ea1e89..3413a403 100644 --- a/snapshot/win/exception_snapshot_win.cc +++ b/snapshot/win/exception_snapshot_win.cc @@ -17,9 +17,9 @@ #include "client/crashpad_client.h" #include "snapshot/capture_memory.h" #include "snapshot/memory_snapshot.h" -#include "snapshot/win/cpu_context_win.h" +#include "snapshot/memory_snapshot_generic.h" #include "snapshot/win/capture_memory_delegate_win.h" -#include "snapshot/win/memory_snapshot_win.h" +#include "snapshot/win/cpu_context_win.h" #include "snapshot/win/process_reader_win.h" #include "util/win/nt_internals.h" diff --git a/snapshot/win/exception_snapshot_win.h b/snapshot/win/exception_snapshot_win.h index 1eed538c..fd4e8543 100644 --- a/snapshot/win/exception_snapshot_win.h +++ b/snapshot/win/exception_snapshot_win.h @@ -36,7 +36,7 @@ class ProcessReaderWin; namespace internal { -class MemorySnapshotWin; +class MemorySnapshotGeneric; union CPUContextUnion { #if defined(ARCH_CPU_X86_FAMILY) @@ -96,7 +96,7 @@ class ExceptionSnapshotWin final : public ExceptionSnapshot { CPUContextUnion context_union_; CPUContext context_; std::vector<uint64_t> codes_; - std::vector<std::unique_ptr<internal::MemorySnapshotWin>> extra_memory_; + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>> extra_memory_; uint64_t thread_id_; uint64_t exception_address_; uint32_t exception_flags_; diff --git a/snapshot/win/memory_snapshot_win.cc b/snapshot/win/memory_snapshot_win.cc deleted file mode 100644 index d56b9520..00000000 --- a/snapshot/win/memory_snapshot_win.cc +++ /dev/null @@ -1,75 +0,0 @@ -// 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. - -#include <memory> - -#include "snapshot/win/memory_snapshot_win.h" - -namespace crashpad { -namespace internal { - -MemorySnapshotWin::MemorySnapshotWin() - : MemorySnapshot(), - process_reader_(nullptr), - address_(0), - size_(0), - initialized_() { -} - -MemorySnapshotWin::~MemorySnapshotWin() { -} - -void MemorySnapshotWin::Initialize(ProcessReaderWin* process_reader, - uint64_t address, - uint64_t size) { - INITIALIZATION_STATE_SET_INITIALIZING(initialized_); - process_reader_ = process_reader; - address_ = address; - DLOG_IF(WARNING, size >= std::numeric_limits<size_t>::max()) - << "size overflow"; - size_ = static_cast<size_t>(size); - INITIALIZATION_STATE_SET_VALID(initialized_); -} - -uint64_t MemorySnapshotWin::Address() const { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return address_; -} - -size_t MemorySnapshotWin::Size() const { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return size_; -} - -bool MemorySnapshotWin::Read(Delegate* delegate) const { - INITIALIZATION_STATE_DCHECK_VALID(initialized_); - - if (size_ == 0) { - return delegate->MemorySnapshotDelegateRead(nullptr, size_); - } - - std::unique_ptr<uint8_t[]> buffer(new uint8_t[size_]); - if (!process_reader_->Memory()->Read(address_, size_, buffer.get())) { - return false; - } - return delegate->MemorySnapshotDelegateRead(buffer.get(), size_); -} - -const MemorySnapshot* MemorySnapshotWin::MergeWithOtherSnapshot( - const MemorySnapshot* other) const { - return MergeWithOtherSnapshotImpl(this, other); -} - -} // namespace internal -} // namespace crashpad diff --git a/snapshot/win/memory_snapshot_win.h b/snapshot/win/memory_snapshot_win.h deleted file mode 100644 index ebc878b8..00000000 --- a/snapshot/win/memory_snapshot_win.h +++ /dev/null @@ -1,75 +0,0 @@ -// 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_SNAPSHOT_WIN_MEMORY_SNAPSHOT_WIN_H_ -#define CRASHPAD_SNAPSHOT_WIN_MEMORY_SNAPSHOT_WIN_H_ - -#include <stdint.h> -#include <sys/types.h> - -#include "base/macros.h" -#include "snapshot/memory_snapshot.h" -#include "snapshot/win/process_reader_win.h" -#include "util/misc/initialization_state_dcheck.h" - -namespace crashpad { -namespace internal { - -//! \brief A MemorySnapshot of a memory region in a process on the running -//! system, when the system runs Windows. -class MemorySnapshotWin final : public MemorySnapshot { - public: - MemorySnapshotWin(); - ~MemorySnapshotWin() override; - - //! \brief Initializes the object. - //! - //! Memory is read lazily. No attempt is made to read the memory snapshot data - //! until Read() is called, and the memory snapshot data is discared when - //! Read() returns. - //! - //! \param[in] process_reader A reader for the process being snapshotted. - //! \param[in] address The base address of the memory region to snapshot, in - //! the snapshot process' address space. - //! \param[in] size The size of the memory region to snapshot. - void Initialize(ProcessReaderWin* process_reader, - uint64_t address, - uint64_t size); - - // MemorySnapshot: - - uint64_t Address() const override; - size_t Size() const override; - bool Read(Delegate* delegate) const override; - const MemorySnapshot* MergeWithOtherSnapshot( - const MemorySnapshot* other) const override; - - private: - template <class T> - friend const MemorySnapshot* MergeWithOtherSnapshotImpl( - const T* self, - const MemorySnapshot* other); - - ProcessReaderWin* process_reader_; // weak - uint64_t address_; - size_t size_; - InitializationStateDcheck initialized_; - - DISALLOW_COPY_AND_ASSIGN(MemorySnapshotWin); -}; - -} // namespace internal -} // namespace crashpad - -#endif // CRASHPAD_SNAPSHOT_WIN_MEMORY_SNAPSHOT_WIN_H_ diff --git a/snapshot/win/module_snapshot_win.cc b/snapshot/win/module_snapshot_win.cc index 49d178a8..c7aaad8d 100644 --- a/snapshot/win/module_snapshot_win.cc +++ b/snapshot/win/module_snapshot_win.cc @@ -19,7 +19,7 @@ #include "base/strings/utf_string_conversions.h" #include "client/crashpad_info.h" #include "client/simple_address_range_bag.h" -#include "snapshot/win/memory_snapshot_win.h" +#include "snapshot/memory_snapshot_generic.h" #include "snapshot/win/pe_image_annotations_reader.h" #include "snapshot/win/pe_image_reader.h" #include "util/misc/tri_state.h" @@ -327,10 +327,10 @@ void ModuleSnapshotWin::GetCrashpadUserMinidumpStreams( } if (list_entry.size != 0) { - std::unique_ptr<internal::MemorySnapshotWin> memory( - new internal::MemorySnapshotWin()); + std::unique_ptr<internal::MemorySnapshotGeneric> memory( + new internal::MemorySnapshotGeneric()); memory->Initialize( - process_reader_, list_entry.base_address, list_entry.size); + process_reader_->Memory(), list_entry.base_address, list_entry.size); streams->push_back(std::make_unique<UserMinidumpStream>( list_entry.stream_type, memory.release())); } diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index d2eef49a..cafe7b42 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -459,7 +459,7 @@ void ProcessSnapshotWin::InitializePebData( void ProcessSnapshotWin::AddMemorySnapshot( WinVMAddress address, WinVMSize size, - std::vector<std::unique_ptr<internal::MemorySnapshotWin>>* into) { + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>>* into) { if (size == 0) return; @@ -480,14 +480,14 @@ void ProcessSnapshotWin::AddMemorySnapshot( } } - into->push_back(std::make_unique<internal::MemorySnapshotWin>()); - into->back()->Initialize(&process_reader_, address, size); + into->push_back(std::make_unique<internal::MemorySnapshotGeneric>()); + into->back()->Initialize(process_reader_.Memory(), address, size); } template <class Traits> void ProcessSnapshotWin::AddMemorySnapshotForUNICODE_STRING( const process_types::UNICODE_STRING<Traits>& us, - std::vector<std::unique_ptr<internal::MemorySnapshotWin>>* into) { + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>>* into) { AddMemorySnapshot(us.Buffer, us.Length, into); } @@ -495,7 +495,7 @@ template <class Traits> void ProcessSnapshotWin::AddMemorySnapshotForLdrLIST_ENTRY( const process_types::LIST_ENTRY<Traits>& le, size_t offset_of_member, - std::vector<std::unique_ptr<internal::MemorySnapshotWin>>* into) { + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>>* into) { // Walk the doubly-linked list of entries, adding the list memory itself, as // well as pointed-to strings. typename Traits::Pointer last = le.Blink; @@ -545,7 +545,7 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock( template <class Traits> void ProcessSnapshotWin::ReadLock( WinVMAddress start, - std::vector<std::unique_ptr<internal::MemorySnapshotWin>>* into) { + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>>* into) { // We're walking the RTL_CRITICAL_SECTION_DEBUG ProcessLocksList, but starting // from an actual RTL_CRITICAL_SECTION, so start by getting to the first // RTL_CRITICAL_SECTION_DEBUG. diff --git a/snapshot/win/process_snapshot_win.h b/snapshot/win/process_snapshot_win.h index 4acfe398..8b0bf526 100644 --- a/snapshot/win/process_snapshot_win.h +++ b/snapshot/win/process_snapshot_win.h @@ -31,6 +31,7 @@ #include "snapshot/exception_snapshot.h" #include "snapshot/memory_map_region_snapshot.h" #include "snapshot/memory_snapshot.h" +#include "snapshot/memory_snapshot_generic.h" #include "snapshot/module_snapshot.h" #include "snapshot/process_snapshot.h" #include "snapshot/system_snapshot.h" @@ -38,7 +39,6 @@ #include "snapshot/unloaded_module_snapshot.h" #include "snapshot/win/exception_snapshot_win.h" #include "snapshot/win/memory_map_region_snapshot_win.h" -#include "snapshot/win/memory_snapshot_win.h" #include "snapshot/win/module_snapshot_win.h" #include "snapshot/win/system_snapshot_win.h" #include "snapshot/win/thread_snapshot_win.h" @@ -154,18 +154,18 @@ class ProcessSnapshotWin final : public ProcessSnapshot { void AddMemorySnapshot( WinVMAddress address, WinVMSize size, - std::vector<std::unique_ptr<internal::MemorySnapshotWin>>* into); + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>>* into); template <class Traits> void AddMemorySnapshotForUNICODE_STRING( const process_types::UNICODE_STRING<Traits>& us, - std::vector<std::unique_ptr<internal::MemorySnapshotWin>>* into); + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>>* into); template <class Traits> void AddMemorySnapshotForLdrLIST_ENTRY( const process_types::LIST_ENTRY<Traits>& le, size_t offset_of_member, - std::vector<std::unique_ptr<internal::MemorySnapshotWin>>* into); + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>>* into); WinVMSize DetermineSizeOfEnvironmentBlock( WinVMAddress start_of_environment_block); @@ -175,10 +175,10 @@ class ProcessSnapshotWin final : public ProcessSnapshot { template <class Traits> void ReadLock( WinVMAddress start, - std::vector<std::unique_ptr<internal::MemorySnapshotWin>>* into); + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>>* into); internal::SystemSnapshotWin system_; - std::vector<std::unique_ptr<internal::MemorySnapshotWin>> extra_memory_; + std::vector<std::unique_ptr<internal::MemorySnapshotGeneric>> extra_memory_; std::vector<std::unique_ptr<internal::ThreadSnapshotWin>> threads_; std::vector<std::unique_ptr<internal::ModuleSnapshotWin>> modules_; std::vector<UnloadedModuleSnapshot> unloaded_modules_; diff --git a/snapshot/win/thread_snapshot_win.cc b/snapshot/win/thread_snapshot_win.cc index f381a4b9..02cc63c5 100644 --- a/snapshot/win/thread_snapshot_win.cc +++ b/snapshot/win/thread_snapshot_win.cc @@ -48,19 +48,20 @@ bool ThreadSnapshotWin::Initialize( if (process_reader->GetProcessInfo().LoggingRangeIsFullyReadable( CheckedRange<WinVMAddress, WinVMSize>(thread_.stack_region_address, thread_.stack_region_size))) { - stack_.Initialize(process_reader, + stack_.Initialize(process_reader->Memory(), thread_.stack_region_address, thread_.stack_region_size); } else { - stack_.Initialize(process_reader, 0, 0); + stack_.Initialize(process_reader->Memory(), 0, 0); } if (process_reader->GetProcessInfo().LoggingRangeIsFullyReadable( CheckedRange<WinVMAddress, WinVMSize>(thread_.teb_address, thread_.teb_size))) { - teb_.Initialize(process_reader, thread_.teb_address, thread_.teb_size); + teb_.Initialize( + process_reader->Memory(), thread_.teb_address, thread_.teb_size); } else { - teb_.Initialize(process_reader, 0, 0); + teb_.Initialize(process_reader->Memory(), 0, 0); } #if defined(ARCH_CPU_X86) diff --git a/snapshot/win/thread_snapshot_win.h b/snapshot/win/thread_snapshot_win.h index 63465803..64ec43de 100644 --- a/snapshot/win/thread_snapshot_win.h +++ b/snapshot/win/thread_snapshot_win.h @@ -24,8 +24,8 @@ #include "build/build_config.h" #include "snapshot/cpu_context.h" #include "snapshot/memory_snapshot.h" +#include "snapshot/memory_snapshot_generic.h" #include "snapshot/thread_snapshot.h" -#include "snapshot/win/memory_snapshot_win.h" #include "snapshot/win/process_reader_win.h" #include "util/misc/initialization_state_dcheck.h" @@ -82,11 +82,11 @@ class ThreadSnapshotWin final : public ThreadSnapshot { #endif } context_union_; CPUContext context_; - MemorySnapshotWin stack_; - MemorySnapshotWin teb_; + MemorySnapshotGeneric stack_; + MemorySnapshotGeneric teb_; ProcessReaderWin::Thread thread_; InitializationStateDcheck initialized_; - std::vector<std::unique_ptr<MemorySnapshotWin>> pointed_to_memory_; + std::vector<std::unique_ptr<MemorySnapshotGeneric>> pointed_to_memory_; DISALLOW_COPY_AND_ASSIGN(ThreadSnapshotWin); }; From e5abe92b2e1e527d519ec616dadb1f833a6c8789 Mon Sep 17 00:00:00 2001 From: Clark DuVall <cduvall@chromium.org> Date: Tue, 11 Jun 2019 09:53:43 -0700 Subject: [PATCH 208/401] Add user minidump stream support for ELF This is very similar to the windows implementation in module_snapshot_win.cc. Bug: crashpad:95 Change-Id: I3858e8bb0009c95395bfb7ca3855c3d937fd49d5 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1641588 Commit-Queue: Clark DuVall <cduvall@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_info.h | 2 +- snapshot/elf/module_snapshot_elf.cc | 36 ++++++++++++++++++-- snapshot/elf/module_snapshot_elf.h | 11 ++++-- snapshot/fuchsia/process_snapshot_fuchsia.cc | 3 +- snapshot/linux/process_snapshot_linux.cc | 3 +- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/client/crashpad_info.h b/client/crashpad_info.h index 5db9a6cd..4c1633f0 100644 --- a/client/crashpad_info.h +++ b/client/crashpad_info.h @@ -208,7 +208,7 @@ struct CrashpadInfo { //! Note that streams will appear in the minidump in the reverse order to //! which they are added. //! - //! TODO(scottmg) This is currently only supported on Windows. + //! TODO(scottmg) This is currently not supported on Mac. //! //! \param[in] stream_type The stream type identifier to use. This should be //! normally be larger than `MINIDUMP_STREAM_TYPE::LastReservedStream` diff --git a/snapshot/elf/module_snapshot_elf.cc b/snapshot/elf/module_snapshot_elf.cc index cfe07dd4..037e7cdb 100644 --- a/snapshot/elf/module_snapshot_elf.cc +++ b/snapshot/elf/module_snapshot_elf.cc @@ -20,6 +20,7 @@ #include "base/files/file_path.h" #include "snapshot/crashpad_types/image_annotation_reader.h" +#include "snapshot/memory_snapshot_generic.h" #include "util/misc/elf_note_types.h" namespace crashpad { @@ -28,14 +29,17 @@ namespace internal { ModuleSnapshotElf::ModuleSnapshotElf(const std::string& name, ElfImageReader* elf_reader, ModuleSnapshot::ModuleType type, - ProcessMemoryRange* process_memory_range) + ProcessMemoryRange* process_memory_range, + const ProcessMemory* process_memory) : ModuleSnapshot(), name_(name), elf_reader_(elf_reader), process_memory_range_(process_memory_range), + process_memory_(process_memory), crashpad_info_(), type_(type), - initialized_() {} + initialized_(), + streams_() {} ModuleSnapshotElf::~ModuleSnapshotElf() = default; @@ -216,7 +220,33 @@ std::set<CheckedRange<uint64_t>> ModuleSnapshotElf::ExtraMemoryRanges() const { std::vector<const UserMinidumpStream*> ModuleSnapshotElf::CustomMinidumpStreams() const { - return std::vector<const UserMinidumpStream*>(); + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + streams_.clear(); + + std::vector<const UserMinidumpStream*> result; + if (!crashpad_info_) + return result; + + for (uint64_t cur = crashpad_info_->UserDataMinidumpStreamHead(); cur;) { + internal::UserDataMinidumpStreamListEntry list_entry; + if (!process_memory_->Read(cur, sizeof(list_entry), &list_entry)) { + LOG(WARNING) << "could not read user data stream entry from " << name_; + return result; + } + + if (list_entry.size != 0) { + auto memory = std::make_unique<internal::MemorySnapshotGeneric>(); + memory->Initialize( + process_memory_, list_entry.base_address, list_entry.size); + streams_.push_back(std::make_unique<UserMinidumpStream>( + list_entry.stream_type, memory.release())); + result.push_back(streams_.back().get()); + } + + cur = list_entry.next; + } + + return result; } } // namespace internal diff --git a/snapshot/elf/module_snapshot_elf.h b/snapshot/elf/module_snapshot_elf.h index be27242f..67ecdf7e 100644 --- a/snapshot/elf/module_snapshot_elf.h +++ b/snapshot/elf/module_snapshot_elf.h @@ -41,11 +41,15 @@ class ModuleSnapshotElf final : public ModuleSnapshot { //! \param[in] name The pathname used to load the module from disk. //! \param[in] elf_reader An image reader for the module. //! \param[in] type The module's type. - //! \param[in] process_memory_range A memory reader for the target process. + //! \param[in] process_memory_range A memory reader giving protected access + //! to the target process. + //! \param[in] process_memory A memory reader for the target process which can + //! be used to initialize a MemorySnapshot. ModuleSnapshotElf(const std::string& name, ElfImageReader* elf_reader, ModuleSnapshot::ModuleType type, - ProcessMemoryRange* process_memory_range); + ProcessMemoryRange* process_memory_range, + const ProcessMemory* process_memory); ~ModuleSnapshotElf() override; //! \brief Initializes the object. @@ -88,9 +92,12 @@ class ModuleSnapshotElf final : public ModuleSnapshot { std::string name_; ElfImageReader* elf_reader_; ProcessMemoryRange* process_memory_range_; + const ProcessMemory* process_memory_; std::unique_ptr<CrashpadInfoReader> crashpad_info_; ModuleType type_; InitializationStateDcheck initialized_; + // Too const-y: https://crashpad.chromium.org/bug/9. + mutable std::vector<std::unique_ptr<const UserMinidumpStream>> streams_; DISALLOW_COPY_AND_ASSIGN(ModuleSnapshotElf); }; diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.cc b/snapshot/fuchsia/process_snapshot_fuchsia.cc index 9ae414ef..1ff758d1 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia.cc @@ -223,7 +223,8 @@ void ProcessSnapshotFuchsia::InitializeModules() { std::make_unique<internal::ModuleSnapshotElf>(reader_module.name, reader_module.reader, reader_module.type, - &memory_range_); + &memory_range_, + process_reader_.Memory()); if (module->Initialize()) { modules_.push_back(std::move(module)); } diff --git a/snapshot/linux/process_snapshot_linux.cc b/snapshot/linux/process_snapshot_linux.cc index bd95ac7a..bada3a95 100644 --- a/snapshot/linux/process_snapshot_linux.cc +++ b/snapshot/linux/process_snapshot_linux.cc @@ -273,7 +273,8 @@ void ProcessSnapshotLinux::InitializeModules() { std::make_unique<internal::ModuleSnapshotElf>(reader_module.name, reader_module.elf_reader, reader_module.type, - &memory_range_); + &memory_range_, + process_reader_.Memory()); if (module->Initialize()) { modules_.push_back(std::move(module)); } From 3a6f57178acfb1df27b7ab26ff29afd5e4cf5f13 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Fri, 14 Jun 2019 09:17:27 -0700 Subject: [PATCH 209/401] [fuchsia] clean up exception handler overload with exception port * Fuchsia migrated its call site to the overload without the exception port as the resume from exception is done outside of Crashpad now * the overload with the koids and the exception port is kept for the standalone Crashpad exception server and handler Bug: fuchsia:ZX-4031 Change-Id: Iec220e2c9bb7b14bdb37b6c008b4fa354dba241d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1659943 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- .../fuchsia/crash_report_exception_handler.cc | 16 +++---------- .../fuchsia/crash_report_exception_handler.h | 24 ------------------- 2 files changed, 3 insertions(+), 37 deletions(-) diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index 34bed289..3ad071a9 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -90,23 +90,13 @@ bool CrashReportExceptionHandler::HandleException( return false; } - return HandleExceptionHandles( - process, thread, exception_port, local_report_id); -} - -bool CrashReportExceptionHandler::HandleExceptionHandles( - const zx::process& process, - const zx::thread& thread, - const zx::unowned_port& exception_port, - UUID* local_report_id) { ScopedThreadResumeAfterException resume(thread, exception_port); return HandleException(process, thread, local_report_id); } -bool CrashReportExceptionHandler::HandleException( - const zx::process& process, - const zx::thread& thread, - UUID* local_report_id) { +bool CrashReportExceptionHandler::HandleException(const zx::process& process, + const zx::thread& thread, + UUID* local_report_id) { ScopedTaskSuspend suspend(process); ProcessSnapshotFuchsia process_snapshot; diff --git a/handler/fuchsia/crash_report_exception_handler.h b/handler/fuchsia/crash_report_exception_handler.h index 57afe7d0..d913dc38 100644 --- a/handler/fuchsia/crash_report_exception_handler.h +++ b/handler/fuchsia/crash_report_exception_handler.h @@ -84,35 +84,11 @@ class CrashReportExceptionHandler { //! \param[out] local_report_id The unique identifier for the report created //! in the local report database. Optional. //! \return `true` on success, or `false` with an error logged. - //! - //! \deprecated Use the port-less version instead and have the caller resume. bool HandleException(uint64_t process_id, uint64_t thread_id, const zx::unowned_port& exception_port, UUID* local_report_id = nullptr); - //! \brief Called when the exception handler server has caught an exception - //! and wants a crash dump to be taken. - //! - //! This function is expected to call `zx_task_resume_from_exception()` in - //! order to complete handling of the exception. - //! - //! \param[in] process The handle to the process which sustained the - //! exception. - //! \param[in] thread The handle to the thread of \a process which sustained - //! the exception. - //! \param[in] exception_port The exception port on which the exception was - //! serviced. This can be used to resume the excepting thread. - //! \param[out] local_report_id The unique identifier for the report created - //! in the local report database. Optional. - //! \return `true` on success, or `false` with an error logged. - //! - //! \deprecated Use the port-less #HandleException instead. - bool HandleExceptionHandles(const zx::process& process, - const zx::thread& thread, - const zx::unowned_port& exception_port, - UUID* local_report_id = nullptr); - //! \brief Called when the exception handler server has caught an exception //! and wants a crash dump to be taken. //! From de22b8d05097b82166866ca16abecbd168bfd7c9 Mon Sep 17 00:00:00 2001 From: Oliver Hunt <ojh@google.com> Date: Tue, 4 Jun 2019 16:32:52 -0700 Subject: [PATCH 210/401] Opt tests into the ambient-replace-as-executable feature Bug: fuchsia:SEC-307 Just adding this feature as a pre-flight step while we restrict the ability for arbitrary processes to make VMOs executable. Change-Id: I4ccdad44855f300edb4e5cbd0b89d5be230a7b4a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1659947 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- test/fuchsia_crashpad_tests.cmx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/fuchsia_crashpad_tests.cmx b/test/fuchsia_crashpad_tests.cmx index 6b666379..74258984 100644 --- a/test/fuchsia_crashpad_tests.cmx +++ b/test/fuchsia_crashpad_tests.cmx @@ -11,7 +11,8 @@ }, "sandbox": { "features": [ - "system-temp" + "system-temp", + "deprecated-ambient-replace-as-executable" ], "services": [ "fuchsia.net.SocketProvider", From d98690a182fdaf3a569031c019d93bd55eb50a87 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 18 Jun 2019 09:48:52 -0700 Subject: [PATCH 211/401] android: enable upload This patch also updates WorkerThread to execute DoWork() when DoWorkNow() has been called, which is relevant when DoWorkNow() and Stop() have both been called. This occurs regularly on Android where the handler's current normal mode is to dump a single process and exit. This change ensures the upload thread has a chance to upload the report before the handler exits. This change should not affect upload on Chrome/WebView/Chromecast which don't pass Crashpad a --url option and are still responsible for their own uploads. Change-Id: Ie5553eafc13714f0438b4b133a92516f7abec153 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1643710 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- handler/crash_report_upload_thread.cc | 7 ------- util/BUILD.gn | 4 +--- util/net/http_transport_none.cc | 26 -------------------------- util/thread/worker_thread.cc | 7 +++++-- util/thread/worker_thread.h | 1 + util/util.gyp | 8 +------- 6 files changed, 8 insertions(+), 45 deletions(-) delete mode 100644 util/net/http_transport_none.cc diff --git a/handler/crash_report_upload_thread.cc b/handler/crash_report_upload_thread.cc index 205d860f..e144bddc 100644 --- a/handler/crash_report_upload_thread.cc +++ b/handler/crash_report_upload_thread.cc @@ -246,12 +246,6 @@ void CrashReportUploadThread::ProcessPendingReport( CrashReportUploadThread::UploadResult CrashReportUploadThread::UploadReport( const CrashReportDatabase::UploadReport* report, std::string* response_body) { -#if defined(OS_ANDROID) - // TODO(jperaza): This method can be enabled on Android after HTTPTransport is - // implemented and Crashpad takes over upload responsibilty on Android. - NOTREACHED(); - return UploadResult::kPermanentFailure; -#else std::map<std::string, std::string> parameters; FileReader* reader = report->Reader(); @@ -338,7 +332,6 @@ CrashReportUploadThread::UploadResult CrashReportUploadThread::UploadReport( } return UploadResult::kSuccess; -#endif // OS_ANDROID } void CrashReportUploadThread::DoWork(const WorkerThread* thread) { diff --git a/util/BUILD.gn b/util/BUILD.gn index cfa4e225..64b74ac7 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -269,7 +269,7 @@ static_library("util") { deps = [] - if (crashpad_is_linux || crashpad_is_fuchsia) { + if (crashpad_is_linux || crashpad_is_fuchsia || crashpad_is_android) { sources += [ "net/http_transport_socket.cc" ] if (crashpad_use_boringssl_for_http_transport_socket) { defines = [ "CRASHPAD_USE_BORINGSSL" ] @@ -283,8 +283,6 @@ static_library("util") { ] } } - } else if (crashpad_is_android) { - sources += [ "net/http_transport_none.cc" ] } if (crashpad_is_linux || crashpad_is_android) { diff --git a/util/net/http_transport_none.cc b/util/net/http_transport_none.cc deleted file mode 100644 index 1c08c1f1..00000000 --- a/util/net/http_transport_none.cc +++ /dev/null @@ -1,26 +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/net/http_transport.h" - -#include "base/logging.h" - -namespace crashpad { - -std::unique_ptr<HTTPTransport> HTTPTransport::Create() { - NOTREACHED(); // TODO(scottmg): https://crashpad.chromium.org/bug/196 - return std::unique_ptr<HTTPTransport>(); -} - -} // namespace crashpad diff --git a/util/thread/worker_thread.cc b/util/thread/worker_thread.cc index 3cf48970..b5dcdb28 100644 --- a/util/thread/worker_thread.cc +++ b/util/thread/worker_thread.cc @@ -33,8 +33,9 @@ class WorkerThreadImpl final : public Thread { if (initial_work_delay_ > 0) semaphore_.TimedWait(initial_work_delay_); - while (self_->running_) { + while (self_->running_ || self_->do_work_now_) { self_->delegate_->DoWork(self_); + self_->do_work_now_ = false; semaphore_.TimedWait(self_->work_interval_); } } @@ -57,7 +58,8 @@ WorkerThread::WorkerThread(double work_interval, : work_interval_(work_interval), delegate_(delegate), impl_(), - running_(false) {} + running_(false), + do_work_now_(false) {} WorkerThread::~WorkerThread() { DCHECK(!running_); @@ -88,6 +90,7 @@ void WorkerThread::Stop() { void WorkerThread::DoWorkNow() { DCHECK(running_); + do_work_now_ = true; impl_->SignalSemaphore(); } diff --git a/util/thread/worker_thread.h b/util/thread/worker_thread.h index 97fb6ecd..0fae0090 100644 --- a/util/thread/worker_thread.h +++ b/util/thread/worker_thread.h @@ -92,6 +92,7 @@ class WorkerThread { Delegate* delegate_; // weak std::unique_ptr<internal::WorkerThreadImpl> impl_; bool running_; + bool do_work_now_; DISALLOW_COPY_AND_ASSIGN(WorkerThread); }; diff --git a/util/util.gyp b/util/util.gyp index 7efec7dc..a438fa69 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -184,7 +184,6 @@ 'net/http_transport.cc', 'net/http_transport.h', 'net/http_transport_mac.mm', - 'net/http_transport_none.cc', 'net/http_transport_win.cc', 'net/url.cc', 'net/url.h', @@ -393,7 +392,7 @@ 'win/safe_terminate_process.asm', ], }], - ['OS=="linux"', { + ['OS=="linux" or OS=="android"', { 'sources': [ 'net/http_transport_socket.cc', ], @@ -402,11 +401,6 @@ 'misc/capture_context_linux.S', ], }], - ['OS!="android"', { - 'sources!': [ - 'net/http_transport_none.cc', - ], - }], ['OS!="linux" and OS!="android"', { 'sources/': [ ['exclude', '^process/'], From b1dbfc65be01c524d996577515f62f82fb74f36e Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 28 Jun 2019 13:44:09 -0700 Subject: [PATCH 212/401] Fuchsia: Update SDK build from cpp to cc Fuchsia recently globally renamed all .cpp to .cc and some of that leaks out into the SDK. Change-Id: Id04c7e18cde77674dc6c1a40f9e378bb182951c8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1682767 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- third_party/fuchsia/BUILD.gn | 50 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index bf001e36..03365e2a 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -57,21 +57,21 @@ if (crashpad_is_in_fuchsia) { source_set("zx") { sources = [ - "$sdk_pkg_path/zx/channel.cpp", - "$sdk_pkg_path/zx/event.cpp", - "$sdk_pkg_path/zx/eventpair.cpp", - "$sdk_pkg_path/zx/fifo.cpp", - "$sdk_pkg_path/zx/guest.cpp", - "$sdk_pkg_path/zx/interrupt.cpp", - "$sdk_pkg_path/zx/job.cpp", - "$sdk_pkg_path/zx/port.cpp", - "$sdk_pkg_path/zx/process.cpp", - "$sdk_pkg_path/zx/resource.cpp", - "$sdk_pkg_path/zx/socket.cpp", - "$sdk_pkg_path/zx/thread.cpp", - "$sdk_pkg_path/zx/timer.cpp", - "$sdk_pkg_path/zx/vmar.cpp", - "$sdk_pkg_path/zx/vmo.cpp", + "$sdk_pkg_path/zx/channel.cc", + "$sdk_pkg_path/zx/event.cc", + "$sdk_pkg_path/zx/eventpair.cc", + "$sdk_pkg_path/zx/fifo.cc", + "$sdk_pkg_path/zx/guest.cc", + "$sdk_pkg_path/zx/interrupt.cc", + "$sdk_pkg_path/zx/job.cc", + "$sdk_pkg_path/zx/port.cc", + "$sdk_pkg_path/zx/process.cc", + "$sdk_pkg_path/zx/resource.cc", + "$sdk_pkg_path/zx/socket.cc", + "$sdk_pkg_path/zx/thread.cc", + "$sdk_pkg_path/zx/timer.cc", + "$sdk_pkg_path/zx/vmar.cc", + "$sdk_pkg_path/zx/vmo.cc", ] public_configs = [ ":zx_config" ] @@ -79,18 +79,18 @@ if (crashpad_is_in_fuchsia) { source_set("fidl_base") { sources = [ - "$sdk_pkg_path/fidl_base/builder.cpp", - "$sdk_pkg_path/fidl_base/decoding.cpp", - "$sdk_pkg_path/fidl_base/encoding.cpp", + "$sdk_pkg_path/fidl_base/builder.cc", + "$sdk_pkg_path/fidl_base/decoding.cc", + "$sdk_pkg_path/fidl_base/encoding.cc", "$sdk_pkg_path/fidl_base/envelope_frames.h", - "$sdk_pkg_path/fidl_base/formatting.cpp", - "$sdk_pkg_path/fidl_base/linearizing.cpp", - "$sdk_pkg_path/fidl_base/message.cpp", - "$sdk_pkg_path/fidl_base/message_buffer.cpp", - "$sdk_pkg_path/fidl_base/message_builder.cpp", - "$sdk_pkg_path/fidl_base/validating.cpp", + "$sdk_pkg_path/fidl_base/formatting.cc", + "$sdk_pkg_path/fidl_base/linearizing.cc", + "$sdk_pkg_path/fidl_base/message.cc", + "$sdk_pkg_path/fidl_base/message_buffer.cc", + "$sdk_pkg_path/fidl_base/message_builder.cc", + "$sdk_pkg_path/fidl_base/validating.cc", "$sdk_pkg_path/fidl_base/visitor.h", - "$sdk_pkg_path/fidl_base/walker.cpp", + "$sdk_pkg_path/fidl_base/walker.cc", "$sdk_pkg_path/fidl_base/walker.h", ] From c68e99cb2df67d09eb38c667fb0b6e3181e27de2 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein <tamird@google.com> Date: Thu, 27 Jun 2019 15:40:26 -0400 Subject: [PATCH 213/401] [all] add fuchsia.{net.NameLookup,posix.socket.Provider} These services will replace fuchsia.net.SocketProvider. Bug: chromium:979080 Change-Id: I8399910e43665f73df40e94ede267c5097997ae7 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1680062 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- test/fuchsia_crashpad_tests.cmx | 42 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/test/fuchsia_crashpad_tests.cmx b/test/fuchsia_crashpad_tests.cmx index 74258984..3381485c 100644 --- a/test/fuchsia_crashpad_tests.cmx +++ b/test/fuchsia_crashpad_tests.cmx @@ -1,22 +1,26 @@ { - "facets": { - "fuchsia.test": { - "system-services": [ - "fuchsia.net.SocketProvider" - ] + "facets": { + "fuchsia.test": { + "system-services": [ + "fuchsia.posix.socket.Provider", + "fuchsia.net.NameLookup", + "fuchsia.net.SocketProvider" + ] + } + }, + "program": { + "binary": "test/crashpad_tests" + }, + "sandbox": { + "features": [ + "system-temp", + "deprecated-ambient-replace-as-executable" + ], + "services": [ + "fuchsia.posix.socket.Provider", + "fuchsia.net.NameLookup", + "fuchsia.net.SocketProvider", + "fuchsia.process.Launcher" + ] } - }, - "program": { - "binary": "test/crashpad_tests" - }, - "sandbox": { - "features": [ - "system-temp", - "deprecated-ambient-replace-as-executable" - ], - "services": [ - "fuchsia.net.SocketProvider", - "fuchsia.process.Launcher" - ] - } } From b19842d25c9ea4f5c6cbf4f368e63422c84df10f Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Fri, 28 Jun 2019 15:20:01 -0700 Subject: [PATCH 214/401] Fix MSan failures Bug: 932205 Change-Id: Ic31986d270634e42bf8c2620f37c434a4cb79b33 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1474271 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- client/crash_report_database_generic.cc | 11 +++++++++ client/crashpad_client_linux_test.cc | 2 +- snapshot/linux/process_reader_linux_test.cc | 8 +++++- util/BUILD.gn | 1 + util/linux/exception_handler_protocol.cc | 5 +++- util/linux/ptrace_broker.cc | 5 ++++ util/linux/ptrace_client.cc | 14 +++++------ util/misc/capture_context_test.cc | 17 +++++++++---- util/misc/memory_sanitizer.h | 27 +++++++++++++++++++++ 9 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 util/misc/memory_sanitizer.h diff --git a/client/crash_report_database_generic.cc b/client/crash_report_database_generic.cc index dab35a10..bbdb2444 100644 --- a/client/crash_report_database_generic.cc +++ b/client/crash_report_database_generic.cc @@ -26,6 +26,7 @@ #include "util/file/directory_reader.h" #include "util/file/filesystem.h" #include "util/misc/initialization_state_dcheck.h" +#include "util/misc/memory_sanitizer.h" namespace crashpad { @@ -1003,6 +1004,11 @@ bool CrashReportDatabaseGeneric::WriteNewMetadata(const base::FilePath& path) { } ReportMetadata metadata; +#if defined(MEMORY_SANITIZER) + // memset() + re-initialization is required to zero padding bytes for MSan. + memset(&metadata, 0, sizeof(metadata)); +#endif // defined(MEMORY_SANITIZER) + metadata = {}; metadata.creation_time = time(nullptr); return LoggingWriteFile(handle.get(), &metadata, sizeof(metadata)); @@ -1023,6 +1029,11 @@ bool CrashReportDatabaseGeneric::WriteMetadata(const base::FilePath& path, } ReportMetadata metadata; +#if defined(MEMORY_SANITIZER) + // memset() + re-initialization is required to zero padding bytes for MSan. + memset(&metadata, 0, sizeof(metadata)); +#endif // defined(MEMORY_SANITIZER) + metadata = {}; metadata.creation_time = report.creation_time; metadata.last_upload_attempt_time = report.last_upload_attempt_time; metadata.upload_attempts = report.upload_attempts; diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index 2ed88251..2bfda5a5 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -348,7 +348,7 @@ class StartHandlerForClientTest { static void HandleCrash(int signo, siginfo_t* siginfo, void* context) { auto state = Get(); - char c; + char c = 0; CHECK(LoggingWriteFile(state->client_sock_, &c, sizeof(c))); ExceptionInformation exception_information; diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index e25b8023..6f993dc7 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -50,6 +50,7 @@ #include "util/linux/direct_ptrace_connection.h" #include "util/misc/address_sanitizer.h" #include "util/misc/from_pointer_cast.h" +#include "util/misc/memory_sanitizer.h" #include "util/synchronization/semaphore.h" #if defined(OS_ANDROID) @@ -337,6 +338,11 @@ class ChildThreadTest : public Multiprocess { thread_pool.StartThreads(kThreadCount, stack_size_); 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.tls = GetTLS(); expectation.stack_address = reinterpret_cast<LinuxVMAddress>(&thread_pool); @@ -771,7 +777,7 @@ class ChildModuleTest : public Multiprocess { ScopedModuleHandle empty_test_module(LoadTestModule(module_name_)); ASSERT_TRUE(empty_test_module.valid()); - char c; + char c = 0; ASSERT_TRUE(LoggingWriteFile(WritePipeHandle(), &c, sizeof(c))); CheckedReadFileAtEOF(ReadPipeHandle()); diff --git a/util/BUILD.gn b/util/BUILD.gn index 64b74ac7..e097203f 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -108,6 +108,7 @@ static_library("util") { "misc/initialization_state_dcheck.h", "misc/lexing.cc", "misc/lexing.h", + "misc/memory_sanitizer.h", "misc/metrics.cc", "misc/metrics.h", "misc/paths.h", diff --git a/util/linux/exception_handler_protocol.cc b/util/linux/exception_handler_protocol.cc index 31b93222..628a4e12 100644 --- a/util/linux/exception_handler_protocol.cc +++ b/util/linux/exception_handler_protocol.cc @@ -20,6 +20,9 @@ ExceptionHandlerProtocol::ClientInformation::ClientInformation() : exception_information_address(0), sanitization_information_address(0) {} ExceptionHandlerProtocol::ClientToServerMessage::ClientToServerMessage() - : version(kVersion), type(kTypeCrashDumpRequest), client_info() {} + : version(kVersion), + type(kTypeCrashDumpRequest), + requesting_thread_stack_address(0), + client_info() {} } // namespace crashpad diff --git a/util/linux/ptrace_broker.cc b/util/linux/ptrace_broker.cc index 6ec0af5b..155a1e0c 100644 --- a/util/linux/ptrace_broker.cc +++ b/util/linux/ptrace_broker.cc @@ -24,6 +24,7 @@ #include "base/logging.h" #include "base/posix/eintr_wrapper.h" +#include "util/misc/memory_sanitizer.h" namespace crashpad { @@ -355,6 +356,10 @@ int PtraceBroker::SendMemory(pid_t pid, VMAddress address, VMSize size) { return 0; } +#if defined(MEMORY_SANITIZER) +// MSan doesn't intercept syscall() and doesn't see that buffer is initialized. +__attribute__((no_sanitize("memory"))) +#endif // defined(MEMORY_SANITIZER) int PtraceBroker::SendDirectory(FileHandle handle) { char buffer[4096]; int rv; diff --git a/util/linux/ptrace_client.cc b/util/linux/ptrace_client.cc index f0d0d50a..f097ad98 100644 --- a/util/linux/ptrace_client.cc +++ b/util/linux/ptrace_client.cc @@ -62,7 +62,7 @@ bool ReceiveAndLogReadError(int sock, const std::string& operation) { } bool AttachImpl(int sock, pid_t tid) { - PtraceBroker::Request request; + PtraceBroker::Request request = {}; request.type = PtraceBroker::Request::kTypeAttach; request.tid = tid; if (!LoggingWriteFile(sock, &request, sizeof(request))) { @@ -136,7 +136,7 @@ PtraceClient::PtraceClient() PtraceClient::~PtraceClient() { if (sock_ != kInvalidFileHandle) { - PtraceBroker::Request request; + PtraceBroker::Request request = {}; request.type = PtraceBroker::Request::kTypeExit; LoggingWriteFile(sock_, &request, sizeof(request)); } @@ -151,7 +151,7 @@ bool PtraceClient::Initialize(int sock, pid_t pid, bool try_direct_memory) { return false; } - PtraceBroker::Request request; + PtraceBroker::Request request = {}; request.type = PtraceBroker::Request::kTypeIs64Bit; request.tid = pid_; @@ -197,7 +197,7 @@ bool PtraceClient::Is64Bit() { bool PtraceClient::GetThreadInfo(pid_t tid, ThreadInfo* info) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - PtraceBroker::Request request; + PtraceBroker::Request request = {}; request.type = PtraceBroker::Request::kTypeGetThreadInfo; request.tid = tid; if (!LoggingWriteFile(sock_, &request, sizeof(request))) { @@ -222,7 +222,7 @@ bool PtraceClient::ReadFileContents(const base::FilePath& path, std::string* contents) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - PtraceBroker::Request request; + PtraceBroker::Request request = {}; request.type = PtraceBroker::Request::kTypeReadFile; request.path.path_length = path.value().size(); @@ -273,7 +273,7 @@ bool PtraceClient::Threads(std::vector<pid_t>* threads) { char path[32]; snprintf(path, base::size(path), "/proc/%d/task", pid_); - PtraceBroker::Request request; + PtraceBroker::Request request = {}; request.type = PtraceBroker::Request::kTypeListDirectory; request.path.path_length = strlen(path); @@ -324,7 +324,7 @@ ssize_t PtraceClient::ReadUpTo(VMAddress address, INITIALIZATION_STATE_DCHECK_VALID(initialized_); char* buffer_c = reinterpret_cast<char*>(buffer); - PtraceBroker::Request request; + PtraceBroker::Request request = {}; request.type = PtraceBroker::Request::kTypeReadMemory; request.tid = pid_; request.iov.base = address; diff --git a/util/misc/capture_context_test.cc b/util/misc/capture_context_test.cc index 42ce6ea2..33f0b5a7 100644 --- a/util/misc/capture_context_test.cc +++ b/util/misc/capture_context_test.cc @@ -21,6 +21,7 @@ #include "gtest/gtest.h" #include "util/misc/address_sanitizer.h" #include "util/misc/capture_context_test_util.h" +#include "util/misc/memory_sanitizer.h" namespace crashpad { namespace test { @@ -33,7 +34,12 @@ namespace { // 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 +#endif // defined(OS_FUCHSIA) + +#if defined(MEMORY_SANITIZER) +// CaptureContext() calls inline assembly and is incompatible with MSan. +__attribute__((no_sanitize("memory"))) +#endif // defined(MEMORY_SANITIZER) void TestCaptureContext() { NativeCPUContext context_1; @@ -49,8 +55,9 @@ void TestCaptureContext() { // reference program counter. uintptr_t pc = ProgramCounterFromContext(context_1); -#if !defined(ADDRESS_SANITIZER) && !defined(ARCH_CPU_MIPS_FAMILY) - // AddressSanitizer can cause enough code bloat that the “nearby” check would +#if !defined(ADDRESS_SANITIZER) && !defined(ARCH_CPU_MIPS_FAMILY) && \ + !defined(MEMORY_SANITIZER) + // Sanitizers can cause enough code bloat that the “nearby” check would // likely fail. const uintptr_t kReferencePC = reinterpret_cast<uintptr_t>(TestCaptureContext); @@ -58,7 +65,7 @@ void TestCaptureContext() { uintptr_t reference) { return actual - reference < 128u; }, pc, kReferencePC); -#endif // !defined(ADDRESS_SANITIZER) +#endif const uintptr_t sp = StackPointerFromContext(context_1); @@ -82,7 +89,7 @@ void TestCaptureContext() { uintptr_t reference) { return reference - actual < 768u; }, sp, kReferenceSP); -#endif // !ADDRESS_SANITIZER +#endif // !defined(ADDRESS_SANITIZER) // Capture the context again, expecting that the stack pointer stays the same // and the program counter increases. Strictly speaking, there’s no guarantee diff --git a/util/misc/memory_sanitizer.h b/util/misc/memory_sanitizer.h new file mode 100644 index 00000000..a3e0d8ee --- /dev/null +++ b/util/misc/memory_sanitizer.h @@ -0,0 +1,27 @@ +// 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_UTIL_MISC_MEMORY_SANITIZER_H_ +#define CRASHPAD_UTIL_MISC_MEMORY_SANITIZER_H_ + +#include "base/compiler_specific.h" +#include "build/build_config.h" + +#if !defined(MEMORY_SANITIZER) +#if HAS_FEATURE(memory_sanitizer) +#define MEMORY_SANITIZER 1 +#endif // HAS_FEATURE(memory_sanitizer) +#endif // !defined(MEMORY_SANITIZER) + +#endif // CRASHPAD_UTIL_MISC_MEMORY_SANITIZER_H_ From 1644b7724de52591bfb57fb8ac7b1a985ace9d58 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Mon, 1 Jul 2019 15:06:30 -0700 Subject: [PATCH 215/401] Add missing build/build_config.h include Change-Id: I1fa215d0d7c3925c27cf45702634269f4f6f2322 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1684438 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- util/misc/capture_context_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/util/misc/capture_context_test.cc b/util/misc/capture_context_test.cc index 33f0b5a7..cf23c2de 100644 --- a/util/misc/capture_context_test.cc +++ b/util/misc/capture_context_test.cc @@ -18,6 +18,7 @@ #include <algorithm> +#include "build/build_config.h" #include "gtest/gtest.h" #include "util/misc/address_sanitizer.h" #include "util/misc/capture_context_test_util.h" From 0f2e2064a102c58f4cd343428b949c9a158e9723 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Mon, 1 Jul 2019 17:05:58 -0700 Subject: [PATCH 216/401] Disable ProcessReaderLinux.ChildWithSplitStack under ASan Change-Id: Ibaee389e64d6e54133a4fb7f4d05cfde0a529821 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1684673 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/linux/process_reader_linux_test.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index 6f993dc7..d7677002 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -469,7 +469,14 @@ class ChildWithSplitStackTest : public Multiprocess { DISALLOW_COPY_AND_ASSIGN(ChildWithSplitStackTest); }; -TEST(ProcessReaderLinux, ChildWithSplitStack) { +// AddressSanitizer with use-after-return detection causes stack variables to +// be allocated on the heap. +#if defined(ADDRESS_SANITIZER) +#define MAYBE_ChildWithSplitStack DISABLED_ChildWithSplitStack +#else +#define MAYBE_ChildWithSplitStack ChildWithSplitStack +#endif +TEST(ProcessReaderLinux, MAYBE_ChildWithSplitStack) { ChildWithSplitStackTest test; test.Run(); } From 1bd77324acfccfe6d319a8926ab63e04e806248a Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 8 Jul 2019 10:53:13 -0400 Subject: [PATCH 217/401] Update mini_chromium to 6ad086b2b6ed3b3169226ee9f311eb2332f332c2 37fd48e63701 Explicitly include stddef.h for size_t b36c61ed9299 Switch to GNU-style strerror_r when needed on Android 6ad086b2b6ed win: Change armasm64 command line arguments Change-Id: I90bb2368be0148d5fc6faa13f2627012aec56966 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1686711 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 33310cd1..20a0fabc 100644 --- a/DEPS +++ b/DEPS @@ -33,7 +33,7 @@ deps = { '8048ece6c16c91acfe0d36d1d3cc0890ab6e945c', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '471390dc9c5a4244364c0f9c5d463ebc78083e2b', + '6ad086b2b6ed3b3169226ee9f311eb2332f332c2', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From cc8fe9ddaba67f08b18afc8cc4ea8d76a3d054bb Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 11 Jul 2019 13:13:08 -0700 Subject: [PATCH 218/401] Implement ProcessSnapshotMinidump time getters Bug: crashpad:10 Change-Id: I0e1449017c60c237eef50818e33cb70e3bfe9b23 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1697057 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- .../minidump/process_snapshot_minidump.cc | 17 ++--- snapshot/minidump/process_snapshot_minidump.h | 3 + .../process_snapshot_minidump_test.cc | 62 +++++++++++++++++++ 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index 63f653d0..ae8c63e7 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -59,6 +59,9 @@ ProcessSnapshotMinidump::ProcessSnapshotMinidump() annotations_simple_map_(), file_reader_(nullptr), process_id_(kInvalidProcessID), + create_time_(0), + user_time_(0), + kernel_time_(0), initialized_() {} ProcessSnapshotMinidump::~ProcessSnapshotMinidump() {} @@ -133,25 +136,22 @@ crashpad::ProcessID ProcessSnapshotMinidump::ParentProcessID() const { void ProcessSnapshotMinidump::SnapshotTime(timeval* snapshot_time) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - snapshot_time->tv_sec = 0; + snapshot_time->tv_sec = header_.TimeDateStamp; snapshot_time->tv_usec = 0; } void ProcessSnapshotMinidump::ProcessStartTime(timeval* start_time) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - start_time->tv_sec = 0; + start_time->tv_sec = create_time_; start_time->tv_usec = 0; } void ProcessSnapshotMinidump::ProcessCPUTimes(timeval* user_time, timeval* system_time) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - user_time->tv_sec = 0; + user_time->tv_sec = user_time_; user_time->tv_usec = 0; - system_time->tv_sec = 0; + system_time->tv_sec = kernel_time_; system_time->tv_usec = 0; } @@ -319,6 +319,9 @@ bool ProcessSnapshotMinidump::InitializeMiscInfo() { // TODO(jperaza): Save the remaining misc info. // https://crashpad.chromium.org/bug/10 process_id_ = info.ProcessId; + create_time_ = info.ProcessCreateTime; + user_time_ = info.ProcessUserTime; + kernel_time_ = info.ProcessKernelTime; } return true; diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 1deac87f..cf2d82bd 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -153,6 +153,9 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::string full_version_; FileReaderInterface* file_reader_; // weak crashpad::ProcessID process_id_; + uint32_t create_time_; + uint32_t user_time_; + uint32_t kernel_time_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ProcessSnapshotMinidump); diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 54ab6eb3..b3e122e0 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -570,6 +570,68 @@ TEST(ProcessSnapshotMinidump, ProcessID) { EXPECT_EQ(process_snapshot.ProcessID(), kTestProcessId); } +TEST(ProcessSnapshotMinidump, SnapshotTime) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.TimeDateStamp = 42; + ASSERT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + ASSERT_TRUE(process_snapshot.Initialize(&string_file)); + + timeval snapshot_time; + process_snapshot.SnapshotTime(&snapshot_time); + EXPECT_EQ(snapshot_time.tv_sec, 42); + EXPECT_EQ(snapshot_time.tv_usec, 0); +} + +TEST(ProcessSnapshotMinidump, MiscTimes) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + ASSERT_TRUE(string_file.Write(&header, sizeof(header))); + + MINIDUMP_MISC_INFO misc_info = {}; + misc_info.SizeOfInfo = sizeof(misc_info); + misc_info.Flags1 = MINIDUMP_MISC1_PROCESS_TIMES; + misc_info.ProcessCreateTime = 42; + misc_info.ProcessUserTime = 43; + misc_info.ProcessKernelTime = 44; + + MINIDUMP_DIRECTORY misc_directory = {}; + misc_directory.StreamType = kMinidumpStreamTypeMiscInfo; + misc_directory.Location.DataSize = sizeof(misc_info); + misc_directory.Location.Rva = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&misc_info, sizeof(misc_info))); + + header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); + ASSERT_TRUE(string_file.Write(&misc_directory, sizeof(misc_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + ASSERT_TRUE(string_file.SeekSet(0)); + ASSERT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + ASSERT_TRUE(process_snapshot.Initialize(&string_file)); + + timeval start_time, user_time, kernel_time; + process_snapshot.ProcessStartTime(&start_time); + process_snapshot.ProcessCPUTimes(&user_time, &kernel_time); + EXPECT_EQ(static_cast<uint32_t>(start_time.tv_sec), + misc_info.ProcessCreateTime); + EXPECT_EQ(start_time.tv_usec, 0); + EXPECT_EQ(static_cast<uint32_t>(user_time.tv_sec), misc_info.ProcessUserTime); + EXPECT_EQ(user_time.tv_usec, 0); + EXPECT_EQ(static_cast<uint32_t>(kernel_time.tv_sec), + misc_info.ProcessKernelTime); + EXPECT_EQ(kernel_time.tv_usec, 0); +} + TEST(ProcessSnapshotMinidump, Threads) { StringFile string_file; From 137506bf1ea769627da04bd6f4d3650f454d5531 Mon Sep 17 00:00:00 2001 From: David Pursell <dpursell@chromium.org> Date: Fri, 12 Jul 2019 09:54:46 -0700 Subject: [PATCH 219/401] [fuchsia] transition off deprecated exception APIs Removes the remaining references to the old port-based exception APIs in favor of the new channel-based APIs. Bug: fuchsia:ZX-4031 Test: runtests on emulator and device Change-Id: Ieac5b66c2f676966d1018d771cab6c8635f12a8f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1700321 Reviewed-by: Francois Rousseau <frousseau@google.com> Commit-Queue: Francois Rousseau <frousseau@google.com> --- client/crashpad_client_fuchsia.cc | 60 ++++++++----------- .../fuchsia/crash_report_exception_handler.cc | 51 ---------------- .../fuchsia/crash_report_exception_handler.h | 19 ------ handler/fuchsia/exception_handler_server.cc | 60 ++++++++++++++----- handler/fuchsia/exception_handler_server.h | 12 ++-- handler/handler_main.cc | 13 ++-- util/BUILD.gn | 1 - util/fuchsia/system_exception_port_key.h | 27 --------- 8 files changed, 85 insertions(+), 158 deletions(-) delete mode 100644 util/fuchsia/system_exception_port_key.h diff --git a/client/crashpad_client_fuchsia.cc b/client/crashpad_client_fuchsia.cc index 523a3e90..3da1f765 100644 --- a/client/crashpad_client_fuchsia.cc +++ b/client/crashpad_client_fuchsia.cc @@ -15,8 +15,8 @@ #include "client/crashpad_client.h" #include <lib/fdio/spawn.h> +#include <lib/zx/channel.h> #include <lib/zx/job.h> -#include <lib/zx/port.h> #include <lib/zx/process.h> #include <zircon/processargs.h> @@ -24,7 +24,6 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" #include "client/client_argv_handling.h" -#include "util/fuchsia/system_exception_port_key.h" namespace crashpad { @@ -44,48 +43,41 @@ bool CrashpadClient::StartHandler( DCHECK_EQ(restartable, false); // Not used on Fuchsia. DCHECK_EQ(asynchronous_start, false); // Not used on Fuchsia. - zx::port exception_port; - zx_status_t status = zx::port::create(0, &exception_port); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_port_create"; - return false; - } - - status = zx::job::default_job()->bind_exception_port( - exception_port, kSystemExceptionPortKey, 0); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_task_bind_exception_port"; - return false; - } - std::vector<std::string> argv_strings = BuildHandlerArgvStrings( handler, database, metrics_dir, url, annotations, arguments); std::vector<const char*> argv; StringVectorToCStringVector(argv_strings, &argv); - // Follow the same protocol as devmgr and crashlogger in Zircon (that is, - // process handle as handle 0, with type USER0, exception port handle as - // handle 1, also with type PA_USER0) so that it's trivial to replace - // crashlogger with crashpad_handler. The exception port is passed on, so - // released here. Currently it is assumed that this process's default job - // handle is the exception port that should be monitored. In the future, it - // might be useful for this to be configurable by the client. - constexpr size_t kActionCount = 2; - fdio_spawn_action_t actions[] = { - {.action = FDIO_SPAWN_ACTION_ADD_HANDLE, - .h = {.id = PA_HND(PA_USER0, 0), .handle = ZX_HANDLE_INVALID}}, - {.action = FDIO_SPAWN_ACTION_ADD_HANDLE, - .h = {.id = PA_HND(PA_USER0, 1), .handle = ZX_HANDLE_INVALID}}, - }; - - status = zx_handle_duplicate( - zx_job_default(), ZX_RIGHT_SAME_RIGHTS, &actions[0].h.handle); + // Set up handles to send to the spawned process: + // 0. PA_USER0 job + // 1. PA_USER0 exception channel + // + // Currently it is assumed that this process's default job handle is the + // exception channel that should be monitored. In the future, it might be + // useful for this to be configurable by the client. + zx::job job; + zx_status_t status = + zx::job::default_job()->duplicate(ZX_RIGHT_SAME_RIGHTS, &job); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_handle_duplicate"; return false; } - actions[1].h.handle = exception_port.release(); + + zx::channel exception_channel; + status = job.create_exception_channel(0, &exception_channel); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_task_create_exception_channel"; + return false; + } + + constexpr size_t kActionCount = 2; + fdio_spawn_action_t actions[] = { + {.action = FDIO_SPAWN_ACTION_ADD_HANDLE, + .h = {.id = PA_HND(PA_USER0, 0), .handle = job.release()}}, + {.action = FDIO_SPAWN_ACTION_ADD_HANDLE, + .h = {.id = PA_HND(PA_USER0, 1), .handle = exception_channel.release()}}, + }; char error_message[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; zx::process child; diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc index 3ad071a9..ad846d29 100644 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ b/handler/fuchsia/crash_report_exception_handler.cc @@ -29,33 +29,6 @@ namespace crashpad { -namespace { - -class ScopedThreadResumeAfterException { - public: - ScopedThreadResumeAfterException(const zx::thread& thread, - const zx::unowned_port& exception_port) - : thread_(thread), exception_port_(exception_port) {} - ~ScopedThreadResumeAfterException() { - DCHECK(thread_->is_valid()); - // Resuming with ZX_RESUME_TRY_NEXT chains to the next handler. In normal - // operation, there won't be another beyond this one, which will result in - // the kernel terminating the process. - zx_status_t status = - thread_->resume_from_exception(*exception_port_, ZX_RESUME_TRY_NEXT); - ZX_LOG_IF(ERROR, status != ZX_OK, status) - << "zx_task_resume_from_exception"; - } - - private: - zx::unowned_thread thread_; - const zx::unowned_port& exception_port_; - - DISALLOW_COPY_AND_ASSIGN(ScopedThreadResumeAfterException); -}; - -} // namespace - CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportDatabase* database, CrashReportUploadThread* upload_thread, @@ -70,30 +43,6 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportExceptionHandler::~CrashReportExceptionHandler() {} -bool CrashReportExceptionHandler::HandleException( - uint64_t process_id, - uint64_t thread_id, - const zx::unowned_port& exception_port, - UUID* local_report_id) { - // TODO(scottmg): This function needs to be instrumented with metrics calls, - // https://crashpad.chromium.org/bug/230. - - zx::process process(GetProcessFromKoid(process_id)); - if (!process.is_valid()) { - // There's no way to resume the thread if the process retrieval fails. - // Assume that the process has been already killed, and bail. - return false; - } - - zx::thread thread(GetThreadHandleByKoid(process, thread_id)); - if (!thread.is_valid()) { - return false; - } - - ScopedThreadResumeAfterException resume(thread, exception_port); - return HandleException(process, thread, local_report_id); -} - bool CrashReportExceptionHandler::HandleException(const zx::process& process, const zx::thread& thread, UUID* local_report_id) { diff --git a/handler/fuchsia/crash_report_exception_handler.h b/handler/fuchsia/crash_report_exception_handler.h index d913dc38..06c432f7 100644 --- a/handler/fuchsia/crash_report_exception_handler.h +++ b/handler/fuchsia/crash_report_exception_handler.h @@ -70,25 +70,6 @@ class CrashReportExceptionHandler { ~CrashReportExceptionHandler(); - //! \brief Called when the exception handler server has caught an exception - //! and wants a crash dump to be taken. - //! - //! This function is expected to call `zx_task_resume_from_exception()` in - //! order to complete handling of the exception. - //! - //! \param[in] process_id The koid of the process which sustained the - //! exception. - //! \param[in] thread_id The koid of the thread which sustained the exception. - //! \param[in] exception_port The exception port on which the exception was - //! serviced. This can be used to resume the excepting thread. - //! \param[out] local_report_id The unique identifier for the report created - //! in the local report database. Optional. - //! \return `true` on success, or `false` with an error logged. - bool HandleException(uint64_t process_id, - uint64_t thread_id, - const zx::unowned_port& exception_port, - UUID* local_report_id = nullptr); - //! \brief Called when the exception handler server has caught an exception //! and wants a crash dump to be taken. //! diff --git a/handler/fuchsia/exception_handler_server.cc b/handler/fuchsia/exception_handler_server.cc index 8c5b1434..e468fe3b 100644 --- a/handler/fuchsia/exception_handler_server.cc +++ b/handler/fuchsia/exception_handler_server.cc @@ -14,44 +14,74 @@ #include "handler/fuchsia/exception_handler_server.h" +#include <lib/zx/exception.h> #include <lib/zx/time.h> -#include <zircon/syscalls/port.h> +#include <zircon/syscalls/exception.h> #include <utility> #include "base/fuchsia/fuchsia_logging.h" #include "base/logging.h" #include "handler/fuchsia/crash_report_exception_handler.h" -#include "util/fuchsia/system_exception_port_key.h" namespace crashpad { ExceptionHandlerServer::ExceptionHandlerServer(zx::job root_job, - zx::port exception_port) + zx::channel exception_channel) : root_job_(std::move(root_job)), - exception_port_(std::move(exception_port)) {} + exception_channel_(std::move(exception_channel)) {} ExceptionHandlerServer::~ExceptionHandlerServer() = default; void ExceptionHandlerServer::Run(CrashReportExceptionHandler* handler) { while (true) { - zx_port_packet_t packet; - zx_status_t status = exception_port_.wait(zx::time::infinite(), &packet); + zx_signals_t signals; + zx_status_t status = exception_channel_.wait_one( + ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, + zx::time::infinite(), + &signals); if (status != ZX_OK) { ZX_LOG(ERROR, status) << "zx_port_wait, aborting"; return; } - if (packet.key != kSystemExceptionPortKey) { - LOG(ERROR) << "unexpected packet key, ignoring"; - continue; - } + if (signals & ZX_CHANNEL_READABLE) { + zx_exception_info_t info; + zx::exception exception; + status = exception_channel_.read(0, + &info, + exception.reset_and_get_address(), + sizeof(info), + 1, + nullptr, + nullptr); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_channel_read, aborting"; + return; + } - bool result = handler->HandleException(packet.exception.pid, - packet.exception.tid, - zx::unowned_port(exception_port_)); - if (!result) { - LOG(ERROR) << "HandleException failed"; + zx::process process; + status = exception.get_process(&process); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_exception_get_process, aborting"; + return; + } + + zx::thread thread; + status = exception.get_thread(&thread); + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "zx_exception_get_thread, aborting"; + return; + } + + bool result = + handler->HandleException(std::move(process), std::move(thread)); + if (!result) { + LOG(ERROR) << "HandleException failed"; + } + } else { + // Job terminated, exit the loop. + return; } } } diff --git a/handler/fuchsia/exception_handler_server.h b/handler/fuchsia/exception_handler_server.h index 1832f02c..85a7b7bd 100644 --- a/handler/fuchsia/exception_handler_server.h +++ b/handler/fuchsia/exception_handler_server.h @@ -15,8 +15,8 @@ #ifndef CRASHPAD_HANDLER_FUCHSIA_EXCEPTION_HANDLER_SERVER_H_ #define CRASHPAD_HANDLER_FUCHSIA_EXCEPTION_HANDLER_SERVER_H_ +#include <lib/zx/channel.h> #include <lib/zx/job.h> -#include <lib/zx/port.h> #include "base/macros.h" @@ -31,11 +31,11 @@ class ExceptionHandlerServer { //! \brief Constructs an ExceptionHandlerServer object. //! //! \param[in] root_job The root of the tree of processes that will be handled - //! by this server. It is assumed that \a exception_port is the exception - //! port of this job. - //! \param[in] exception_port The exception port that this server will + //! by this server. It is assumed that \a exception_channel is the + // exception channel of this job. + //! \param[in] exception_channel The exception channel that this server will //! monitor. - ExceptionHandlerServer(zx::job root_job, zx::port exception_port); + ExceptionHandlerServer(zx::job root_job, zx::channel exception_channel); ~ExceptionHandlerServer(); //! \brief Runs the exception-handling server. @@ -46,7 +46,7 @@ class ExceptionHandlerServer { private: zx::job root_job_; - zx::port exception_port_; + zx::channel exception_channel_; DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServer); }; diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 724168ee..f33a79fe 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -86,6 +86,9 @@ #include <zircon/process.h> #include <zircon/processargs.h> +#include <lib/zx/channel.h> +#include <lib/zx/job.h> + #include "handler/fuchsia/crash_report_exception_handler.h" #include "handler/fuchsia/exception_handler_server.h" #elif defined(OS_LINUX) @@ -982,18 +985,18 @@ int HandlerMain(int argc, // crashpad_handler. zx::job root_job(zx_take_startup_handle(PA_HND(PA_USER0, 0))); if (!root_job.is_valid()) { - LOG(ERROR) << "no process handle passed in startup handle 0"; + LOG(ERROR) << "no job handle passed in startup handle 0"; return EXIT_FAILURE; } - zx::port exception_port(zx_take_startup_handle(PA_HND(PA_USER0, 1))); - if (!exception_port.is_valid()) { - LOG(ERROR) << "no exception port handle passed in startup handle 1"; + zx::channel exception_channel(zx_take_startup_handle(PA_HND(PA_USER0, 1))); + if (!exception_channel.is_valid()) { + LOG(ERROR) << "no exception channel handle passed in startup handle 1"; return EXIT_FAILURE; } ExceptionHandlerServer exception_handler_server(std::move(root_job), - std::move(exception_port)); + std::move(exception_channel)); #elif defined(OS_LINUX) || defined(OS_ANDROID) ExceptionHandlerServer exception_handler_server; #endif // OS_MACOSX diff --git a/util/BUILD.gn b/util/BUILD.gn index e097203f..00c52e1e 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -422,7 +422,6 @@ static_library("util") { "fuchsia/koid_utilities.h", "fuchsia/scoped_task_suspend.cc", "fuchsia/scoped_task_suspend.h", - "fuchsia/system_exception_port_key.h", "misc/capture_context_fuchsia.S", "misc/paths_fuchsia.cc", "process/process_memory_fuchsia.cc", diff --git a/util/fuchsia/system_exception_port_key.h b/util/fuchsia/system_exception_port_key.h deleted file mode 100644 index 0bbae690..00000000 --- a/util/fuchsia/system_exception_port_key.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 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_FUCHSIA_EXCEPTION_PORT_KEY_H_ -#define CRASHPAD_UTIL_FUCHSIA_EXCEPTION_PORT_KEY_H_ - -namespace crashpad { - -//! \brief The key used in `zx_task_bind_exception_port()` and packet -//! processing. This matches the value that Zircon's `devmgr` and -//! `crashlogger` use for interoperability, for now. -constexpr uint64_t kSystemExceptionPortKey = 1166444u; - -} // namespace crashpad - -#endif // CRASHPAD_UTIL_FUCHSIA_EXCEPTION_PORT_KEY_H_ From b946fdd438be31575610fe08a92449acd1ca8e58 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Mon, 15 Jul 2019 10:23:10 -0700 Subject: [PATCH 220/401] Refactor CrashpadHandlerMain into its own target Currently crashpad's CrashpadHandlerMain can not be overridden. Change it to be in its own target so that implementers can override it if they so choose. Bug: chromium:973167 Change-Id: Ie44eac24c54948154ff550072560732faf621739 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1682932 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- handler/BUILD.gn | 14 ++++++++++++++ handler/crashpad_handler_main.cc | 33 ++++++++++++++++++++++++++++++++ handler/handler_main.cc | 12 ------------ 3 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 handler/crashpad_handler_main.cc diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 67c77e5f..548073ce 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -88,6 +88,20 @@ static_library("handler") { } } +if (crashpad_is_android) { + # CrashpadHandlerMain is defined in a separate target so that it can be + # overriden by implementers + source_set("crashpad_handler_main") { + sources = [ + "crashpad_handler_main.cc", + ] + + deps = [ + ":handler", + ] + } +} + source_set("handler_test") { testonly = true diff --git a/handler/crashpad_handler_main.cc b/handler/crashpad_handler_main.cc new file mode 100644 index 00000000..34b3f669 --- /dev/null +++ b/handler/crashpad_handler_main.cc @@ -0,0 +1,33 @@ +// 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. + +#include "handler/handler_main.h" + +namespace crashpad { + +extern "C" { +//! \brief The `main()` entry point for Android libraries. +//! +//! This symbol is the entry point for crashpad when it is dynamically loaded +//! using /system/bin/linker. +//! +//! \sa CrashpadClient::StartHandlerWithLinkerAtCrash() +__attribute__((visibility("default"), used)) int CrashpadHandlerMain( + int argc, + char* argv[]) { + return HandlerMain(argc, argv, nullptr); +} +} // extern "C" + +} // namespace crashpad diff --git a/handler/handler_main.cc b/handler/handler_main.cc index f33a79fe..05a2e7b4 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -506,18 +506,6 @@ class ScopedStoppable { } // namespace -#if defined(OS_ANDROID) - -extern "C" { -__attribute__((visibility("default"), used)) int CrashpadHandlerMain( - int argc, - char* argv[]) { - return HandlerMain(argc, argv, nullptr); -} -} // extern "C" - -#endif // OS_ANDROID - int HandlerMain(int argc, char* argv[], const UserStreamDataSources* user_stream_sources) { From c05bd0574b6838c93dffb679fe6ec1036719350c Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 15 Jul 2019 14:08:41 -0700 Subject: [PATCH 221/401] include missing header Change-Id: I64d248aecbf894da88ea95d70320d91368967832 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1702845 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- snapshot/minidump/minidump_stream.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snapshot/minidump/minidump_stream.h b/snapshot/minidump/minidump_stream.h index 4356b2c6..2b0ac2e1 100644 --- a/snapshot/minidump/minidump_stream.h +++ b/snapshot/minidump/minidump_stream.h @@ -19,6 +19,8 @@ #include <vector> +#include "base/macros.h" + namespace crashpad { //! \brief Stores a minidump stream along with its stream ID. From a079d8b15b3e38e8541fcfc6eda9068f4f75d91e Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 17 Jul 2019 08:39:49 -0700 Subject: [PATCH 222/401] Fix TSan failure Start the server thread after setting the ptrace strategy pointer, otherwise TSan can't tell that the access is synchronized by the order of operations in the test. Bug: crashpad:304 Change-Id: I8be975916eba4e6cb933634596702df07d45219a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1706792 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- handler/linux/exception_handler_server_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index 7ef007e0..ea10db35 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -272,12 +272,12 @@ class ExceptionHandlerServerTest : public testing::TestWithParam<bool> { void ExpectCrashDumpUsingStrategy(PtraceStrategyDecider::Strategy strategy, bool succeeds) { - ScopedStopServerAndJoinThread stop_server(Server(), ServerThread()); - ServerThread()->Start(); - Server()->SetPtraceStrategyDecider( std::make_unique<MockPtraceStrategyDecider>(strategy)); + ScopedStopServerAndJoinThread stop_server(Server(), ServerThread()); + ServerThread()->Start(); + CrashDumpTest test(this, succeeds); test.Run(); } From 4f0a0f5d36285ee9afdc75ccb153dd0e3aebe1f2 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 17 Jul 2019 08:44:11 -0700 Subject: [PATCH 223/401] Make ExceptionHandlerServer::keep_running_ atomic ExceptionHandlerServer::keep_running_ is used to implement synchronization across threads (e.g. ExceptionHandlerServer::Stop) but the variable is not atomic. This causes TSan failures and could also lead to incorrect compiler optimizations. Bug: crashpad:304 Change-Id: I3cf5c083d70b6be903e16dbb6feb8fecea2aa1b8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1706793 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- handler/linux/exception_handler_server.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index 9752195e..b6251e14 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -18,6 +18,7 @@ #include <stdint.h> #include <sys/socket.h> +#include <atomic> #include <memory> #include <unordered_map> @@ -181,7 +182,7 @@ class ExceptionHandlerServer { std::unique_ptr<PtraceStrategyDecider> strategy_decider_; Delegate* delegate_; ScopedFileHandle pollfd_; - bool keep_running_; + std::atomic<bool> keep_running_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServer); From 79b59b0a8f60eb10b9f8b4938094c96e783d8d6b Mon Sep 17 00:00:00 2001 From: Adam Kallai <kadam@inf.u-szeged.hu> Date: Wed, 17 Jul 2019 16:07:23 +0200 Subject: [PATCH 224/401] Add support for capture CPU context on Windows on ARM64 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. The obj file is generated from the capture_context_win_arm64.asm by armasm64 macro assembler. If this asm file is modified, the obj file needs to be updated. Change-Id: Id5a4a949997a27b04815aeb79b2540d30a52d34c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1632749 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/BUILD.gn | 13 ++++- util/misc/capture_context_fuchsia.S | 4 +- util/misc/capture_context_linux.S | 4 +- util/misc/capture_context_win_arm64.asm | 64 ++++++++++++++++++++++++ util/misc/capture_context_win_arm64.obj | Bin 0 -> 614 bytes 5 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 util/misc/capture_context_win_arm64.asm create mode 100644 util/misc/capture_context_win_arm64.obj diff --git a/util/BUILD.gn b/util/BUILD.gn index 00c52e1e..86ae6793 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -405,8 +405,17 @@ static_library("util") { "win/safe_terminate_process.asm", ] } else { - # TODO: Add assembly code of CaptureContext for Windows ARM64. - sources += [ "misc/capture_context_broken.cc" ] + # 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 { sources += [ diff --git a/util/misc/capture_context_fuchsia.S b/util/misc/capture_context_fuchsia.S index 21aefad0..0ebc7f7f 100644 --- a/util/misc/capture_context_fuchsia.S +++ b/util/misc/capture_context_fuchsia.S @@ -116,7 +116,7 @@ CAPTURECONTEXT_SYMBOL: movq 0x90(%rdi), %rax movq 0x28(%rdi), %r8 - // TODO(scottmg): save floating-point registers. + // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. popfq @@ -166,7 +166,7 @@ CAPTURECONTEXT_SYMBOL: // Restore x1 from the saved context. ldr x1, [x0, #0xc0] - // TODO(scottmg): save floating-point registers. + // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. ret diff --git a/util/misc/capture_context_linux.S b/util/misc/capture_context_linux.S index 657a979a..de71e723 100644 --- a/util/misc/capture_context_linux.S +++ b/util/misc/capture_context_linux.S @@ -282,7 +282,7 @@ CAPTURECONTEXT_SYMBOL2: // Restore r1. ldr r1, [r0, #0x24] - // TODO(jperaza): save floating-point registers. + // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. mov PC, LR @@ -326,7 +326,7 @@ CAPTURECONTEXT_SYMBOL2: // Restore x1 from the saved context. ldr x1, [x0, #0xc0] - // TODO(jperaza): save floating-point registers. + // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. ret #elif defined(__mips__) diff --git a/util/misc/capture_context_win_arm64.asm b/util/misc/capture_context_win_arm64.asm new file mode 100644 index 00000000..5630698f --- /dev/null +++ b/util/misc/capture_context_win_arm64.asm @@ -0,0 +1,64 @@ +; 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. + + EXPORT |?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z| + AREA |.text|, CODE +|?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z| PROC + ; Save general purpose registers in context.regs[i]. + ; The original x0 can't be recovered. + stp x0, x1, [x0, #0x008] + stp x2, x3, [x0, #0x018] + stp x4, x5, [x0, #0x028] + stp x6, x7, [x0, #0x038] + stp x8, x9, [x0, #0x048] + stp x10, x11, [x0, #0x058] + stp x12, x13, [x0, #0x068] + stp x14, x15, [x0, #0x078] + stp x16, x17, [x0, #0x088] + stp x18, x19, [x0, #0x098] + stp x20, x21, [x0, #0x0a8] + stp x22, x23, [x0, #0x0b8] + stp x24, x25, [x0, #0x0c8] + stp x26, x27, [x0, #0x0d8] + stp x28, x29, [x0, #0x0e8] + + ; The original LR can't be recovered. + str LR, [x0, #0x0f8] + + ; Use x1 as a scratch register. + mov x1, SP + str x1, [x0, #0x100] ; context.sp + + ; The link register holds the return address for this function. + str LR, [x0, #0x108] ; context.pc + + ; pstate should hold SPSR but NZCV are the only bits we know about. + mrs x1, NZCV + + ; Enable Control flags, such as CONTEXT_ARM64, CONTEXT_CONTROL, + ; CONTEXT_INTEGER + ldr w1, =0x00400003 + + ; Set ControlFlags /0x000/ and pstate /0x004/ at the same time. + str x1, [x0, #0x000] + + ; Restore x1 from the saved context. + ldr x1, [x0, #0x010] + + ; TODO(https://crashpad.chromium.org/bug/300): save floating-point registers + + ret + ENDP + + END diff --git a/util/misc/capture_context_win_arm64.obj b/util/misc/capture_context_win_arm64.obj new file mode 100644 index 0000000000000000000000000000000000000000..11c76a1aae15f8331d37063a3adc5e6ad37fcc8f GIT binary patch literal 614 zcmYdU#l-MIOFuS-k%57S0Rr?&QY%WJY!H<K#YjR73JeYjdMT+%rRgfcF!3os#t9e) zN;@zJI5D&^tYqq8T*)$pX(ihn=9L^vSXOeaVO`0yg>5C@9`=<2M>tjro#9+5a)oQ9 z*d6Yb5>I$mO1<G-Df5MIrCbfe&xgzm6B!#Ae#*5l{A6^pzS_vZAOUplPeu-hp9h%Z zuQ4+?Ft7ma`v}AxK<vT5C<wCN*(#>EC^;s%D6u%BATb5OC@sm%iOJ0@2FfKCl#~{w z#wX|Jfjk{wo|zY)Sd?pKqL-hP#lT?0U?a%P#K7<kWE>dqF$gfs$Yf;j%}g%JFV0UZ zQP2p|RB#OPRq#y&iYPc17pLYX<)jt?RXZf-=N9N?rp(A>X8ix3fdS~wwA92BJp%&) zpe#g0FD)}C6=F2QKcJd)7K&V*Sey$ri~%_ofuY5~%m|7{RDc|VKyL!ofZ`AnfI=4p sK;|$p7y(IpXGq97LjukL7RU|`k&Y1ou8yJc&i;NOt`Q*)4h~Ta0HmRmk^lez literal 0 HcmV?d00001 From 2fb8f98d675ee177fb15731b08a02027d83615da Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 17 Jul 2019 22:32:42 -0700 Subject: [PATCH 225/401] Add external CrashpadHandlerMain declaration External callers might also want to call CrashpadHandlerMain, so provide an externally visibile declaration on Android. Bug: 973167 Change-Id: Ib9c2a2070e87563acd8af25f8634f1c88ce6681f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1707897 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- handler/crashpad_handler_main.cc | 8 ++------ handler/handler_main.h | 11 +++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/handler/crashpad_handler_main.cc b/handler/crashpad_handler_main.cc index 34b3f669..b47488ef 100644 --- a/handler/crashpad_handler_main.cc +++ b/handler/crashpad_handler_main.cc @@ -17,17 +17,13 @@ namespace crashpad { extern "C" { -//! \brief The `main()` entry point for Android libraries. -//! -//! This symbol is the entry point for crashpad when it is dynamically loaded -//! using /system/bin/linker. -//! -//! \sa CrashpadClient::StartHandlerWithLinkerAtCrash() + __attribute__((visibility("default"), used)) int CrashpadHandlerMain( int argc, char* argv[]) { return HandlerMain(argc, argv, nullptr); } + } // extern "C" } // namespace crashpad diff --git a/handler/handler_main.h b/handler/handler_main.h index af01dbe7..25265411 100644 --- a/handler/handler_main.h +++ b/handler/handler_main.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_HANDLER_HANDLER_MAIN_H_ #define CRASHPAD_HANDLER_HANDLER_MAIN_H_ +#include "build/build_config.h" #include "handler/user_stream_data_source.h" namespace crashpad { @@ -34,6 +35,16 @@ int HandlerMain(int argc, char* argv[], const UserStreamDataSources* user_stream_sources); +#if defined(OS_ANDROID) +//! \brief The `main()` entry point for Android libraries. +//! +//! This symbol is the entry point for crashpad when it is dynamically loaded +//! using /system/bin/linker. +//! +//! \sa CrashpadClient::StartHandlerWithLinkerAtCrash() +extern "C" int CrashpadHandlerMain(int argc, char* argv[]); +#endif + } // namespace crashpad #endif // CRASHPAD_HANDLER_HANDLER_MAIN_H_ From e163efb37210c93ac6761a704ed8e44a994ba514 Mon Sep 17 00:00:00 2001 From: Istvan Romai <iromai@inf.u-szeged.hu> Date: Wed, 12 Jun 2019 11:03:07 +0200 Subject: [PATCH 226/401] Added CPU revision implementation for ARM64 Change-Id: I42e6c76715dfd44fa87c8bbd56b8903f76cef87c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1655468 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/win/system_snapshot_win.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/snapshot/win/system_snapshot_win.cc b/snapshot/win/system_snapshot_win.cc index 2a93baaf..826a3f33 100644 --- a/snapshot/win/system_snapshot_win.cc +++ b/snapshot/win/system_snapshot_win.cc @@ -158,9 +158,10 @@ uint32_t SystemSnapshotWin::CPURevision() const { uint8_t adjusted_model = model + (extended_model << 4); return (adjusted_family << 16) | (adjusted_model << 8) | stepping; #elif defined(ARCH_CPU_ARM64) - // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30 - // This is the same as SystemSnapshotLinux::CPURevision. - return 0; + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + + return system_info.wProcessorRevision; #else #error Unsupported Windows Arch #endif From 63782c8333c98850c08b4cc000dba97fe533127f Mon Sep 17 00:00:00 2001 From: Istvan Romai <iromai@inf.u-szeged.hu> Date: Wed, 24 Jul 2019 15:19:03 +0200 Subject: [PATCH 227/401] Added Windows on ARM support to SystemSnapshot::CPUVendor Bug: crashpad:297 Change-Id: I1430f86986efdd7bc3c5494ce1838653c64524d6 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1647167 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- snapshot/win/system_snapshot_win.cc | 42 ++++++++++++++++++++---- snapshot/win/system_snapshot_win_test.cc | 11 +++++-- util/win/process_info_test.cc | 13 +------- util/win/scoped_registry_key.h | 34 +++++++++++++++++++ 4 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 util/win/scoped_registry_key.h diff --git a/snapshot/win/system_snapshot_win.cc b/snapshot/win/system_snapshot_win.cc index 826a3f33..f07c4f67 100644 --- a/snapshot/win/system_snapshot_win.cc +++ b/snapshot/win/system_snapshot_win.cc @@ -28,6 +28,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "util/win/module_version.h" +#include "util/win/scoped_registry_key.h" namespace crashpad { @@ -76,11 +77,9 @@ SystemSnapshotWin::SystemSnapshotWin() os_version_minor_(0), os_version_bugfix_(0), os_server_(false), - initialized_() { -} + initialized_() {} -SystemSnapshotWin::~SystemSnapshotWin() { -} +SystemSnapshotWin::~SystemSnapshotWin() {} void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); @@ -191,9 +190,38 @@ std::string SystemSnapshotWin::CPUVendor() const { *reinterpret_cast<int*>(vendor + 8) = cpu_info[2]; return std::string(vendor, sizeof(vendor)); #elif defined(ARCH_CPU_ARM64) - // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30 - // This is the same as SystemSnapshotLinux::CPURevision. - return std::string(); + HKEY key; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", + 0, + KEY_QUERY_VALUE, + &key) != ERROR_SUCCESS) { + return std::string(); + } + + crashpad::ScopedRegistryKey scoped_key(key); + DWORD type; + wchar_t vendor_identifier[1024]; + DWORD vendor_identifier_size = sizeof(vendor_identifier); + + if (RegQueryValueEx(key, + L"VendorIdentifier", + nullptr, + &type, + reinterpret_cast<BYTE*>(vendor_identifier), + &vendor_identifier_size) != ERROR_SUCCESS || + type != REG_SZ) { + return std::string(); + } + + std::string return_value; + DCHECK_EQ(vendor_identifier_size % sizeof(wchar_t), 0u); + base::UTF16ToUTF8(vendor_identifier, + vendor_identifier_size / sizeof(wchar_t), + &return_value); + + return return_value.c_str(); #else #error Unsupported Windows Arch #endif diff --git a/snapshot/win/system_snapshot_win_test.cc b/snapshot/win/system_snapshot_win_test.cc index a8ccd32b..3a76b9e9 100644 --- a/snapshot/win/system_snapshot_win_test.cc +++ b/snapshot/win/system_snapshot_win_test.cc @@ -17,6 +17,7 @@ #include <sys/time.h> #include <time.h> +#include <regex> #include <string> #include "build/build_config.h" @@ -73,10 +74,14 @@ TEST_F(SystemSnapshotWinTest, CPUCount) { TEST_F(SystemSnapshotWinTest, CPUVendor) { std::string cpu_vendor = system_snapshot().CPUVendor(); - - // There are a variety of other values, but we don't expect to run our tests - // on them. +#if defined(ARCH_CPU_X86_FAMILY) EXPECT_TRUE(cpu_vendor == "GenuineIntel" || cpu_vendor == "AuthenticAMD"); +#elif defined(ARCH_CPU_ARM64) + std::regex cpu_vendor_regex("[a-zA-Z0-9 \\-.]+"); + EXPECT_TRUE(std::regex_match(cpu_vendor, cpu_vendor_regex)); +#else +#error Unsupported Windows Arch +#endif } #if defined(ARCH_CPU_X86_FAMILY) diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc index c7abdb6f..59aaa7a9 100644 --- a/util/win/process_info_test.cc +++ b/util/win/process_info_test.cc @@ -38,6 +38,7 @@ #include "util/win/get_function.h" #include "util/win/handle.h" #include "util/win/scoped_handle.h" +#include "util/win/scoped_registry_key.h" namespace crashpad { namespace test { @@ -528,18 +529,6 @@ TEST(ProcessInfo, ReadableRanges) { &bytes_read)); } -struct ScopedRegistryKeyCloseTraits { - static HKEY InvalidValue() { - return nullptr; - } - static void Free(HKEY key) { - RegCloseKey(key); - } -}; - -using ScopedRegistryKey = - base::ScopedGeneric<HKEY, ScopedRegistryKeyCloseTraits>; - TEST(ProcessInfo, Handles) { ScopedTempDir temp_dir; diff --git a/util/win/scoped_registry_key.h b/util/win/scoped_registry_key.h new file mode 100644 index 00000000..4393dc20 --- /dev/null +++ b/util/win/scoped_registry_key.h @@ -0,0 +1,34 @@ +// 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_UTIL_WIN_SCOPED_REGISTRY_KEY_H_ +#define CRASHPAD_UTIL_WIN_SCOPED_REGISTRY_KEY_H_ + +#include <windows.h> + +#include "base/scoped_generic.h" + +namespace crashpad { + +struct ScopedRegistryKeyCloseTraits { + static HKEY InvalidValue() { return nullptr; } + static void Free(HKEY key) { RegCloseKey(key); } +}; + +using ScopedRegistryKey = + base::ScopedGeneric<HKEY, ScopedRegistryKeyCloseTraits>; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_WIN_SCOPED_REGISTRY_KEY_H_ \ No newline at end of file From 8b8066297c2ad13737f5b0e1333ae9b851438907 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 30 Jul 2019 10:27:55 -0700 Subject: [PATCH 228/401] [fuchsia] remove obsolete FIDL string.cc include the code moved to string.h and the SDK no longer includes that source file TESTED=fix the broken Fuchsia bots Change-Id: I2ad39e6bc4d90e7a79ab380899bd20a84d0df465 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1724907 Reviewed-by: Francois Rousseau <frousseau@google.com> Commit-Queue: Francois Rousseau <frousseau@google.com> --- third_party/fuchsia/BUILD.gn | 1 - 1 file changed, 1 deletion(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 03365e2a..b7f69e61 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -102,7 +102,6 @@ if (crashpad_is_in_fuchsia) { "$sdk_pkg_path/fidl_cpp_base/clone.cc", "$sdk_pkg_path/fidl_cpp_base/decoder.cc", "$sdk_pkg_path/fidl_cpp_base/encoder.cc", - "$sdk_pkg_path/fidl_cpp_base/string.cc", ] public_configs = [ From 2faae40e8e63208666c5a401955fe9f85e58a5de Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Tue, 30 Jul 2019 20:23:07 -0400 Subject: [PATCH 229/401] Fuchsia: Update docs to mention target_os in .gclient Change-Id: I1f26373413d7f427cc7081a1221e5d7238b5fd97 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1726696 Reviewed-by: Francois Rousseau <frousseau@google.com> Commit-Queue: Scott Graham <scottmg@chromium.org> --- doc/developing.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/developing.md b/doc/developing.md index af557a53..f4a95e13 100644 --- a/doc/developing.md +++ b/doc/developing.md @@ -106,6 +106,18 @@ GN and Ninja are part of the [depot_tools](https://www.chromium.org/developers/how-tos/depottools). There’s no need to install them separately. +#### Fuchsia + +In order to instruct gclient to download the Fuchsia SDK, you need to add the +following to `~/crashpad/.gclient`. + +``` +target_os=["fuchsia"] +``` + +If you're using this tree to develop for multiple targets, you can also add +other entries to the the list (e.g. `target_os=["fuchsia", "mac"]`). + #### Optional Linux Configs To pull and use Crashpad's version of clang and sysroot, make the following From 1b2f448720eef4e7fc93e6193a5f4100cafe0846 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Wed, 31 Jul 2019 01:22:27 -0400 Subject: [PATCH 230/401] Fuchsia: de-port generate_dump generate_dump is not being used on Fuchsia (because only the system-reporter version of Fuchsia Crashpad is actively used). GetProcessFromKoid() is becoming increasingly difficult to implement, so simply de-port generate_dump until we actually need it again in the future (if ever). Removes GetRootJob(). Change-Id: Ib5e5d8e79177506da4b2e0e0382f3fdd2502840b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1726695 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Francois Rousseau <frousseau@google.com> --- tools/BUILD.gn | 62 ++++++++++++++++--------------- tools/generate_dump.cc | 22 ----------- util/fuchsia/koid_utilities.cc | 68 ---------------------------------- util/fuchsia/koid_utilities.h | 7 ---- 4 files changed, 32 insertions(+), 127 deletions(-) diff --git a/tools/BUILD.gn b/tools/BUILD.gn index cd1e95f4..ffcd08f3 100644 --- a/tools/BUILD.gn +++ b/tools/BUILD.gn @@ -56,38 +56,40 @@ crashpad_executable("crashpad_http_upload") { ] } -crashpad_executable("generate_dump") { - sources = [ - "generate_dump.cc", - ] - - deps = [ - ":tool_support", - "../build:default_exe_manifest_win", - "../compat", - "../minidump", - "../snapshot", - "../third_party/mini_chromium:base", - "../util", - ] - - if (crashpad_is_mac) { - # This would be better as a config so that it could be shared with - # exception_port_tool, but configs can’t alter “inputs”. - # https://crbug.com/781858. - inputs = [ - "mac/sectaskaccess_info.plist", +if (!crashpad_is_fuchsia) { + crashpad_executable("generate_dump") { + sources = [ + "generate_dump.cc", ] - ldflags = [ - "-sectcreate", - "__TEXT", - "__info_plist", - rebase_path(inputs[0], root_build_dir), - ] - } - if (crashpad_is_win) { - cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union + deps = [ + ":tool_support", + "../build:default_exe_manifest_win", + "../compat", + "../minidump", + "../snapshot", + "../third_party/mini_chromium:base", + "../util", + ] + + if (crashpad_is_mac) { + # This would be better as a config so that it could be shared with + # exception_port_tool, but configs can’t alter “inputs”. + # https://crbug.com/781858. + inputs = [ + "mac/sectaskaccess_info.plist", + ] + ldflags = [ + "-sectcreate", + "__TEXT", + "__info_plist", + rebase_path(inputs[0], root_build_dir), + ] + } + + if (crashpad_is_win) { + cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union + } } } diff --git a/tools/generate_dump.cc b/tools/generate_dump.cc index 76bb86e4..2113a1ab 100644 --- a/tools/generate_dump.cc +++ b/tools/generate_dump.cc @@ -47,12 +47,6 @@ #include "snapshot/win/process_snapshot_win.h" #include "util/win/scoped_process_suspend.h" #include "util/win/xp_compat.h" -#elif defined(OS_FUCHSIA) -#include <lib/zx/process.h> - -#include "snapshot/fuchsia/process_snapshot_fuchsia.h" -#include "util/fuchsia/koid_utilities.h" -#include "util/fuchsia/scoped_task_suspend.h" #elif defined(OS_LINUX) || defined(OS_ANDROID) #include "snapshot/linux/process_snapshot_linux.h" #endif // OS_MACOSX @@ -167,12 +161,6 @@ int GenerateDumpMain(int argc, char* argv[]) { PLOG(ERROR) << "could not open process " << options.pid; return EXIT_FAILURE; } -#elif defined(OS_FUCHSIA) - zx::process process = GetProcessFromKoid(options.pid); - if (!process.is_valid()) { - LOG(ERROR) << "could not open process " << options.pid; - return EXIT_FAILURE; - } #endif // OS_MACOSX if (options.dump_path.empty()) { @@ -191,11 +179,6 @@ int GenerateDumpMain(int argc, char* argv[]) { if (options.suspend) { suspend.reset(new ScopedProcessSuspend(process.get())); } -#elif defined(OS_FUCHSIA) - std::unique_ptr<ScopedTaskSuspend> suspend; - if (options.suspend) { - suspend.reset(new ScopedTaskSuspend(process)); - } #endif // OS_MACOSX #if defined(OS_MACOSX) @@ -213,11 +196,6 @@ int GenerateDumpMain(int argc, char* argv[]) { 0)) { return EXIT_FAILURE; } -#elif defined(OS_FUCHSIA) - ProcessSnapshotFuchsia process_snapshot; - if (!process_snapshot.Initialize(process)) { - return EXIT_FAILURE; - } #elif defined(OS_LINUX) || defined(OS_ANDROID) // TODO(jperaza): https://crashpad.chromium.org/bug/30. ProcessSnapshotLinux process_snapshot; diff --git a/util/fuchsia/koid_utilities.cc b/util/fuchsia/koid_utilities.cc index 288f04b9..09c7e541 100644 --- a/util/fuchsia/koid_utilities.cc +++ b/util/fuchsia/koid_utilities.cc @@ -48,33 +48,6 @@ T CastHandle(zx::handle handle) { return T(std::move(handle)); } -zx::job GetRootJob() { - ScopedFileHandle sysinfo( - LoggingOpenFileForRead(base::FilePath("/dev/misc/sysinfo"))); - if (!sysinfo.is_valid()) - return zx::job(); - - zx::channel channel; - zx_status_t status = fdio_get_service_handle(sysinfo.release(), - channel.reset_and_get_address()); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "fdio_get_service_handle"; - return zx::job(); - } - - zx::handle root_job; - zx_status_t fidl_status = fuchsia_sysinfo_DeviceGetRootJob( - channel.get(), &status, root_job.reset_and_get_address()); - if (fidl_status != ZX_OK) { - ZX_LOG(ERROR, fidl_status) << "fuchsia_sysinfo_DeviceGetRootJob"; - return zx::job(); - } else if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "fuchsia_sysinfo_DeviceGetRootJob"; - return zx::job(); - } - return CastHandle<zx::job>(std::move(root_job)); -} - // Returns null handle if |koid| is not found or an error occurs. If |was_found| // is non-null then it will be set, to distinguish not-found from other errors. template <typename T, typename U> @@ -92,35 +65,6 @@ T GetChildHandleByKoid(const U& parent, zx_koid_t child_koid, bool* was_found) { return CastHandle<T>(std::move(handle)); } -// Returns an invalid handle if the |koid| was found, but was of the wrong -// type, or we could not open a handle to it. -zx::process FindProcess(const zx::job& job, zx_koid_t koid, bool* was_found) { - DCHECK(!*was_found); - - // Look for |koid| as a direct descendent of |job|. - auto process = GetChildHandleByKoid<zx::process>(job, koid, was_found); - if (*was_found) { - // |koid| was found. |process| may still be null, e.g. if a handle could not - // be opened to it. - return process; - } - - // |koid| was not found under |job|, so search child jobs, if any. - // Since we only hold a handle to the job we are currently enumerating, child - // jobs may go away mid-enumeration. - for (auto child_koid : GetChildKoids(job, ZX_INFO_JOB_CHILDREN)) { - zx::job child_job = GetChildHandleByKoid<zx::job>(job, child_koid, nullptr); - if (!child_job.is_valid()) - continue; - zx::process process = FindProcess(child_job, koid, was_found); - if (*was_found) - return process; - } - - DCHECK(!*was_found); - return zx::process(); -} - } // namespace std::vector<zx_koid_t> GetChildKoids(const zx::object_base& parent_object, @@ -195,16 +139,4 @@ zx_koid_t GetKoidForHandle(const zx::object_base& object) { return info.koid; } -// TODO(scottmg): This implementation uses some debug/temporary/hacky APIs and -// ioctls that are currently the only way to go from pid to handle. This should -// hopefully eventually be replaced by more or less a single -// zx_debug_something() syscall. -zx::process GetProcessFromKoid(zx_koid_t koid) { - bool was_found = false; - zx::process result = FindProcess(GetRootJob(), koid, &was_found); - if (!result.is_valid()) - LOG(ERROR) << "process " << koid << " not found"; - return result; -} - } // namespace crashpad diff --git a/util/fuchsia/koid_utilities.h b/util/fuchsia/koid_utilities.h index 9848dced..8859bc51 100644 --- a/util/fuchsia/koid_utilities.h +++ b/util/fuchsia/koid_utilities.h @@ -71,13 +71,6 @@ std::vector<zx::thread> GetHandlesForThreadKoids( zx::thread GetThreadHandleByKoid(const zx::process& parent, zx_koid_t child_koid); -//! \brief Gets a process handle given the process' koid. -//! -//! \param[in] koid The process id. -//! \return A zx_handle_t (owned by a base::ScopedZxHandle) for the process. If -//! the handle is invalid, an error will have been logged. -zx::process GetProcessFromKoid(zx_koid_t koid); - //! \brief Retrieves the koid for a given object handle. //! //! \param[in] object The handle for which the koid is to be retrieved. From da3384a7088a0d96d69e4a3332126b11d97fae27 Mon Sep 17 00:00:00 2001 From: Wesley Aptekar-Cassels <wesleyac@google.com> Date: Tue, 6 Aug 2019 13:31:26 -0400 Subject: [PATCH 231/401] Fuchsia: remove fuchsia.net.SocketProvider from cmx fuchsia.net.SocketProvider has been replaced by fuchsia.net.NameLookup and fuchsia.posix.socket.Provider. Change-Id: I03e16b4bf432b1560a1b9f9415fc79a94854ad27 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1739507 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- test/fuchsia_crashpad_tests.cmx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/fuchsia_crashpad_tests.cmx b/test/fuchsia_crashpad_tests.cmx index 3381485c..b0edbb46 100644 --- a/test/fuchsia_crashpad_tests.cmx +++ b/test/fuchsia_crashpad_tests.cmx @@ -2,9 +2,8 @@ "facets": { "fuchsia.test": { "system-services": [ - "fuchsia.posix.socket.Provider", "fuchsia.net.NameLookup", - "fuchsia.net.SocketProvider" + "fuchsia.posix.socket.Provider" ] } }, @@ -17,9 +16,8 @@ "deprecated-ambient-replace-as-executable" ], "services": [ - "fuchsia.posix.socket.Provider", "fuchsia.net.NameLookup", - "fuchsia.net.SocketProvider", + "fuchsia.posix.socket.Provider", "fuchsia.process.Launcher" ] } From 70d10eb6296bd7bf93d536bf8efc3e51a8683f75 Mon Sep 17 00:00:00 2001 From: Venkatesh Srinivas <venkateshs@chromium.org> Date: Wed, 7 Aug 2019 11:02:57 -0400 Subject: [PATCH 232/401] client_win: Switch Release Load/Acq Store->Rel Store/Acq Load client_win used a non-standard/poorly defined "Acquire Store" and "Release Load" pair to have handlers notify when they changed state and to wait for handlers to change state. Acquire stores and Release Loads are not expressable in C++11 atomics and even at face value did not provide useful semantics here (code waiting for a handler to change state wants to see the handler's stores.) Change-Id: I8d08d0d7baf9979406557ec2b90fea4cd51892bc Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1741716 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_win.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index 143dc4f1..c1c3ff14 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -96,7 +96,7 @@ CRITICAL_SECTION g_critical_section_with_debug_info; void SetHandlerStartupState(StartupState state) { DCHECK(state == StartupState::kSucceeded || state == StartupState::kFailed); - base::subtle::Acquire_Store(&g_handler_startup_state, + base::subtle::Release_Store(&g_handler_startup_state, static_cast<base::subtle::AtomicWord>(state)); } @@ -104,7 +104,7 @@ StartupState BlockUntilHandlerStartedOrFailed() { // Wait until we know the handler has either succeeded or failed to start. base::subtle::AtomicWord startup_state; while ( - (startup_state = base::subtle::Release_Load(&g_handler_startup_state)) == + (startup_state = base::subtle::Acquire_Load(&g_handler_startup_state)) == static_cast<int>(StartupState::kNotReady)) { Sleep(1); } From 08f070325eb75670f355c97707a6d231e47d5c94 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <pcc@google.com> Date: Tue, 13 Aug 2019 17:55:25 -0700 Subject: [PATCH 233/401] Fix the build with NDK r20. NDK r20 provides a declaration of android_get_device_api_level() at API level 29, and an inline definition at older API levels. The latter conflicts with crashpad's definition, so stop defining it if the NDK is new enough. Bug: chromium:891999 Change-Id: If58542c9d6b5315f823f2509f168f2cb79141e3f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1739512 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- compat/android/android/api-level.cc | 4 ++-- compat/android/android/api-level.h | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/compat/android/android/api-level.cc b/compat/android/android/api-level.cc index 1a553368..c29ec1a0 100644 --- a/compat/android/android/api-level.cc +++ b/compat/android/android/api-level.cc @@ -21,7 +21,7 @@ #include "dlfcn_internal.h" -#if __ANDROID_API__ < 29 +#if __NDK_MAJOR__ < 20 extern "C" { @@ -47,4 +47,4 @@ int android_get_device_api_level() { } // extern "C" -#endif // __ANDROID_API__ < 29 +#endif // __NDK_MAJOR__ < 20 diff --git a/compat/android/android/api-level.h b/compat/android/android/api-level.h index 03794cbd..bfff9af5 100644 --- a/compat/android/android/api-level.h +++ b/compat/android/android/api-level.h @@ -16,23 +16,24 @@ #define CRASHPAD_COMPAT_ANDROID_ANDROID_API_LEVEL_H_ #include_next <android/api-level.h> +#include <android/ndk-version.h> #include <sys/cdefs.h> -#if __ANDROID_API__ < 29 +#if __NDK_MAJOR__ < 20 #ifdef __cplusplus extern "C" { #endif // Returns the API level of the device or -1 if it can't be determined. This -// function is provided by Bionic at API 29. +// function is provided by NDK r20. int android_get_device_api_level(); #ifdef __cplusplus } // extern "C" #endif -#endif // __ANDROID_API__ < 29 +#endif // __NDK_MAJOR__ < 20 #endif // CRASHPAD_COMPAT_ANDROID_ANDROID_API_LEVEL_H_ From a34bca8611b6263632a94d3d773df076c81d03dd Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Wed, 14 Aug 2019 13:48:25 -0700 Subject: [PATCH 234/401] Disable warning when building gmock tests On recent clang builds, some gmock tests are failing to build: FAILED: obj/third_party/gtest/gtest/googlemock/test/gmock_all_test.gmock-actions_test.o ../../third_party/linux/clang/linux-amd64/bin/clang++ -MMD -MF obj/third_party/gtest/gtest/googlemock/test/gmock_all_test.gmock-actions_test.o.d -D_FILE_OFFSET_BITS=64 -DGUNIT_NO_GOOGLE3=1 -I../../third_party/gtest/gtest/googlemock -I../../third_party/gtest/gtest/googletest -I../../third_party/gtest/gtest/googlemock/include -I../../third_party/gtest/gtest/googletest/include -Wall -Wendif-labels -Werror -Wextra -Wextra-semi -Wno-missing-field-initializers -Wno-unused-parameter -Wsign-compare -fno-exceptions -fno-rtti -fno-strict-aliasing -fobjc-call-cxx-cdtors -fstack-protector-all -fvisibility-inlines-hidden -fvisibility=hidden -Wheader-hygiene -Wnewline-eof -Wstring-conversion -stdlib=libstdc++ -fPIC -Wimplicit-fallthrough --sysroot=../../third_party/linux/sysroot -pthread -Wexit-time-destructors -Wno-unused-private-field -std=c++14 -Wno-inconsistent-missing-override -c ../../third_party/gtest/gtest/googlemock/test/gmock-actions_test.cc -o obj/third_party/gtest/gtest/googlemock/test/gmock_all_test.gmock-actions_test.o ../../third_party/gtest/gtest/googlemock/test/gmock-actions_test.cc:109:37: error: 'wchar_t' cannot be signed or unsigned [-Wsigned-unsigned-wchar] EXPECT_EQ(0U, BuiltInDefaultValue<unsigned wchar_t>::Get()); ^ ... Disable this warning for now. Change-Id: Ibd41a6fc12d1f13eca5227775e2559ccf3baf229 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1754722 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- third_party/gtest/BUILD.gn | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index c2058e23..286a1d9e 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -267,6 +267,17 @@ if (crashpad_is_in_chromium) { config("gmock_private_config") { visibility = [ ":*" ] include_dirs = [ "gtest/googlemock" ] + if (crashpad_is_clang && (crashpad_is_linux || crashpad_is_fuchsia)) { + cflags_cc = [ + # This seems a bit questionable: + # https://github.com/google/googletest/blob/bf6df7eaee5cfaafe2655fab143f348eba98c9af/googlemock/include/gmock/internal/gmock-internal-utils.h#L109 + # and causes a warning/error on recent clangs (Linux/Fuchsia currently + # have this, other platforms don't yet). + # Temporarily disable this warning for building gmock tests until + # internal CL 263406158 lands and rolls. + "-Wno-signed-unsigned-wchar", + ] + } } config("gmock_public_config") { From 5a0e18e41761a494c800aa6c97bad5face2ead8e Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Tue, 13 Aug 2019 10:57:12 -0700 Subject: [PATCH 235/401] Refactor 'whitelist' -> 'annotations whitelist' In preparation for an upcoming change that will introduce a second whitelist (for memory ranges), rename variables/functions to explicitly reference the annotations whitelist. Bug: chromium:973167 Change-Id: I1bf232e370990571230a247f9d9022d56ba4fedf Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1752361 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- handler/linux/crash_report_exception_handler.cc | 6 +++--- .../sanitized/process_snapshot_sanitized_test.cc | 6 +++--- snapshot/sanitized/sanitization_information.cc | 13 +++++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 345e234d..e65b26e8 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -140,7 +140,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( ProcessSnapshot* snapshot = nullptr; ProcessSnapshotSanitized sanitized; - std::vector<std::string> whitelist; + std::vector<std::string> annotations_whitelist; if (info.sanitization_information_address) { SanitizationInformation sanitization_info; ProcessMemoryRange range; @@ -157,7 +157,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( !ReadAnnotationsWhitelist( range, sanitization_info.annotations_whitelist_address, - &whitelist)) { + &annotations_whitelist)) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kSanitizationInitializationFailed); return false; @@ -165,7 +165,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( if (!sanitized.Initialize(&process_snapshot, sanitization_info.annotations_whitelist_address - ? &whitelist + ? &annotations_whitelist : nullptr, sanitization_info.target_module_address, sanitization_info.sanitize_stacks)) { diff --git a/snapshot/sanitized/process_snapshot_sanitized_test.cc b/snapshot/sanitized/process_snapshot_sanitized_test.cc index f4c852f9..e01ff324 100644 --- a/snapshot/sanitized/process_snapshot_sanitized_test.cc +++ b/snapshot/sanitized/process_snapshot_sanitized_test.cc @@ -252,12 +252,12 @@ class SanitizeTest : public MultiprocessExec { ExpectAnnotations(&snapshot, /* sanitized= */ false); ExpectStackData(&snapshot, addrs, /* sanitized= */ false); - std::vector<std::string> whitelist; - whitelist.push_back(kWhitelistedAnnotationName); + std::vector<std::string> annotations_whitelist; + annotations_whitelist.push_back(kWhitelistedAnnotationName); ProcessSnapshotSanitized sanitized; ASSERT_TRUE(sanitized.Initialize( - &snapshot, &whitelist, addrs.module_address, true)); + &snapshot, &annotations_whitelist, addrs.module_address, true)); ExpectAnnotations(&sanitized, /* sanitized= */ true); ExpectStackData(&sanitized, addrs, /* sanitized= */ true); diff --git a/snapshot/sanitized/sanitization_information.cc b/snapshot/sanitized/sanitization_information.cc index f7be9b08..d97f706f 100644 --- a/snapshot/sanitized/sanitization_information.cc +++ b/snapshot/sanitized/sanitization_information.cc @@ -21,9 +21,9 @@ namespace crashpad { namespace { template <typename Pointer> -bool ReadWhitelist(const ProcessMemoryRange& memory, - VMAddress whitelist_address, - std::vector<std::string>* whitelist) { +bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory, + VMAddress whitelist_address, + std::vector<std::string>* whitelist) { if (!whitelist_address) { return true; } @@ -53,9 +53,10 @@ bool ReadWhitelist(const ProcessMemoryRange& memory, bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory, VMAddress whitelist_address, std::vector<std::string>* whitelist) { - return memory.Is64Bit() - ? ReadWhitelist<uint64_t>(memory, whitelist_address, whitelist) - : ReadWhitelist<uint32_t>(memory, whitelist_address, whitelist); + return memory.Is64Bit() ? ReadAnnotationsWhitelist<uint64_t>( + memory, whitelist_address, whitelist) + : ReadAnnotationsWhitelist<uint32_t>( + memory, whitelist_address, whitelist); } } // namespace crashpad From bde5196af5088294a987e79fbcc9d4115e8f6df6 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Wed, 14 Aug 2019 16:13:35 -0700 Subject: [PATCH 236/401] Add ProcessMemorySanitized The ProcessMemorySanitized implementation only allows reads to a given process if it falls within a given whitelist of memory ranges. This ensures that 'sanitized' snapshots only allow reading memory that was explicitly allowed. Bug: crashpad:263, chromium:973167 Change-Id: I72712d7ea3cabfd49cc91ffbe563cb349e6fcfdb Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1752593 Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- util/BUILD.gn | 3 + util/process/process_memory.h | 3 + util/process/process_memory_sanitized.cc | 65 +++++++++++++++++++ util/process/process_memory_sanitized.h | 62 ++++++++++++++++++ util/process/process_memory_sanitized_test.cc | 64 ++++++++++++++++++ util/util.gyp | 2 + util/util_test.gyp | 5 ++ 7 files changed, 204 insertions(+) create mode 100644 util/process/process_memory_sanitized.cc create mode 100644 util/process/process_memory_sanitized.h create mode 100644 util/process/process_memory_sanitized_test.cc diff --git a/util/BUILD.gn b/util/BUILD.gn index 86ae6793..3819b153 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -329,6 +329,8 @@ static_library("util") { "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", ] } @@ -651,6 +653,7 @@ source_set("util_test") { "linux/scoped_ptrace_attach_test.cc", "linux/socket_test.cc", "misc/capture_context_test_util_linux.cc", + "process/process_memory_sanitized_test.cc", ] } diff --git a/util/process/process_memory.h b/util/process/process_memory.h index 32e7472f..eeb78e97 100644 --- a/util/process/process_memory.h +++ b/util/process/process_memory.h @@ -126,6 +126,9 @@ class ProcessMemory { bool has_size, VMSize size, std::string* string) const; + + // Allow ProcessMemorySanitized to call ReadUpTo. + friend class ProcessMemorySanitized; }; } // namespace crashpad diff --git a/util/process/process_memory_sanitized.cc b/util/process/process_memory_sanitized.cc new file mode 100644 index 00000000..cafe5aef --- /dev/null +++ b/util/process/process_memory_sanitized.cc @@ -0,0 +1,65 @@ +// 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. + +#include "util/process/process_memory_sanitized.h" + +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <algorithm> +#include <limits> + +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" + +namespace crashpad { + +ProcessMemorySanitized::ProcessMemorySanitized() + : ProcessMemory(), memory_(nullptr), whitelist_() {} + +ProcessMemorySanitized::~ProcessMemorySanitized() {} + +bool ProcessMemorySanitized::Initialize( + const ProcessMemory* memory, + const std::vector<std::pair<VMAddress, VMAddress>>* whitelist) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + memory_ = memory; + if (whitelist) + whitelist_ = *whitelist; + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +ssize_t ProcessMemorySanitized::ReadUpTo(VMAddress address, + size_t size, + void* buffer) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + VMAddress end = address + size; + for (auto&& entry : whitelist_) { + if (address >= entry.first && address < entry.second && + end >= entry.first && end <= entry.second) { + return memory_->ReadUpTo(address, size, buffer); + } + } + + DLOG(ERROR) + << "ProcessMemorySanitized failed to read unwhitelisted region. address=" + << address << " size=" << size; + return 0; +} + +} // namespace crashpad diff --git a/util/process/process_memory_sanitized.h b/util/process/process_memory_sanitized.h new file mode 100644 index 00000000..44439636 --- /dev/null +++ b/util/process/process_memory_sanitized.h @@ -0,0 +1,62 @@ +// 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_UTIL_PROCESS_PROCESS_MEMORY_SANITIZED_H_ +#define CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_SANITIZED_H_ + +#include <sys/types.h> + +#include <utility> +#include <vector> + +#include "base/macros.h" +#include "util/misc/address_types.h" +#include "util/misc/initialization_state_dcheck.h" +#include "util/process/process_memory.h" + +namespace crashpad { + +//! \brief Sanitized access to the memory of another process. +class ProcessMemorySanitized final : public ProcessMemory { + public: + ProcessMemorySanitized(); + ~ProcessMemorySanitized(); + + //! \brief Initializes this object to read memory from the underlying + //! \a memory object if the memory range is in the provided \a whitelist. + //! + //! This method must be called successfully prior to calling any other method + //! in this class. + //! + //! \param[in] memory The memory object to read whitelisted regions from. + //! \param[in] whitelist A whitelist of memory regions. + //! + //! \return `true` on success, `false` on failure with a message logged. + bool Initialize( + const ProcessMemory* memory, + const std::vector<std::pair<VMAddress, VMAddress>>* whitelist); + + private: + ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) const override; + + const ProcessMemory* memory_; + InitializationStateDcheck initialized_; + std::vector<std::pair<VMAddress, VMAddress>> whitelist_; + + DISALLOW_COPY_AND_ASSIGN(ProcessMemorySanitized); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_PROCESS_PROCESS_MEMORY_SANITIZED_H_ diff --git a/util/process/process_memory_sanitized_test.cc b/util/process/process_memory_sanitized_test.cc new file mode 100644 index 00000000..ff5c9445 --- /dev/null +++ b/util/process/process_memory_sanitized_test.cc @@ -0,0 +1,64 @@ +// 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. + +#include "util/process/process_memory_sanitized.h" + +#include "gtest/gtest.h" +#include "test/process_type.h" +#include "util/misc/from_pointer_cast.h" +#include "util/process/process_memory_native.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(ProcessMemorySanitized, DenyOnEmptyWhitelist) { + ProcessMemoryNative memory; + ASSERT_TRUE(memory.Initialize(GetSelfProcess())); + + char c = 42; + char out; + + ProcessMemorySanitized san_null; + san_null.Initialize(&memory, nullptr); + EXPECT_FALSE(san_null.Read(FromPointerCast<VMAddress>(&c), 1, &out)); + + std::vector<std::pair<VMAddress, VMAddress>> whitelist; + ProcessMemorySanitized san_blank; + san_blank.Initialize(&memory, &whitelist); + EXPECT_FALSE(san_blank.Read(FromPointerCast<VMAddress>(&c), 1, &out)); +} + +TEST(ProcessMemorySanitized, WhitelistingWorks) { + ProcessMemoryNative memory; + ASSERT_TRUE(memory.Initialize(GetSelfProcess())); + + char str[4] = "ABC"; + char out[4]; + + std::vector<std::pair<VMAddress, VMAddress>> whitelist; + whitelist.push_back(std::make_pair(FromPointerCast<VMAddress>(str + 1), + FromPointerCast<VMAddress>(str + 2))); + + ProcessMemorySanitized sanitized; + sanitized.Initialize(&memory, &whitelist); + + EXPECT_FALSE(sanitized.Read(FromPointerCast<VMAddress>(str), 1, &out)); + EXPECT_TRUE(sanitized.Read(FromPointerCast<VMAddress>(str + 1), 1, &out)); + EXPECT_FALSE(sanitized.Read(FromPointerCast<VMAddress>(str + 2), 1, &out)); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/util.gyp b/util/util.gyp index a438fa69..c7d735fb 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -395,6 +395,8 @@ ['OS=="linux" or OS=="android"', { 'sources': [ 'net/http_transport_socket.cc', + 'util/process_memory_sanitized.cc', + 'util/process_memory_sanitized.h', ], }, { # else: OS!="linux" 'sources!': [ diff --git a/util/util_test.gyp b/util/util_test.gyp index 573162e6..c819e6db 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -154,6 +154,11 @@ ['exclude', '^net/http_transport_test\\.cc$'], ] }], + ['OS=="linux" or OS=="android"', { + 'sources': [ + 'util/process_memory_sanitized_test.cc', + ], + }], ['OS!="linux" and OS!="android"', { 'sources/': [ ['exclude', '^process/'], From 6225d7890687204fdd4b69eb2646e16e98739d41 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne <pcc@google.com> Date: Thu, 15 Aug 2019 09:37:31 -0700 Subject: [PATCH 237/401] Don't use a regex to test the CPU vendor string. This test will break if there is an unusual character in the vendor string. Moreover, std::regex is banned in Chromium so the test is blocking the roll. Probably all that can meaningfully be tested here is that the vendor string is non-empty, so do that instead. Change-Id: I60ea52e1b52c4d8e467518d03088815dcb5e3fce Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1756327 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Peter Collingbourne <pcc@chromium.org> --- snapshot/win/system_snapshot_win_test.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/snapshot/win/system_snapshot_win_test.cc b/snapshot/win/system_snapshot_win_test.cc index 3a76b9e9..d93c654c 100644 --- a/snapshot/win/system_snapshot_win_test.cc +++ b/snapshot/win/system_snapshot_win_test.cc @@ -17,7 +17,6 @@ #include <sys/time.h> #include <time.h> -#include <regex> #include <string> #include "build/build_config.h" @@ -77,8 +76,7 @@ TEST_F(SystemSnapshotWinTest, CPUVendor) { #if defined(ARCH_CPU_X86_FAMILY) EXPECT_TRUE(cpu_vendor == "GenuineIntel" || cpu_vendor == "AuthenticAMD"); #elif defined(ARCH_CPU_ARM64) - std::regex cpu_vendor_regex("[a-zA-Z0-9 \\-.]+"); - EXPECT_TRUE(std::regex_match(cpu_vendor, cpu_vendor_regex)); + EXPECT_FALSE(cpu_vendor.empty()); #else #error Unsupported Windows Arch #endif From 5a4c2f2b8359019f331eac260cb1443e07c3e9e1 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 15 Aug 2019 12:38:52 -0700 Subject: [PATCH 238/401] Plumb in support for ProcessMemorySanitized A previous change added a ProcessMemorySanitized class, in this change plumb support for ProcessMemorySanitized into ProcessSnapshotSanitized. This involves reading whitelisted regions using the a new field in the SanitizationInformation struct and returning an initialized ProcessMemorySanitized object from ProcessSnapshotSanitized::Memory(). Bug: crashpad:263, chromium:973167 Change-Id: I121c5a584a1704ad043757c113099978a9ec2f4e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1754737 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- .../linux/crash_report_exception_handler.cc | 11 ++-- .../sanitized/process_snapshot_sanitized.cc | 6 ++- .../sanitized/process_snapshot_sanitized.h | 4 ++ .../process_snapshot_sanitized_test.cc | 35 +++++++++++-- .../sanitized/sanitization_information.cc | 52 +++++++++++++++++++ snapshot/sanitized/sanitization_information.h | 33 ++++++++++++ 6 files changed, 133 insertions(+), 8 deletions(-) diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index e65b26e8..1688df79 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -141,6 +141,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( ProcessSnapshot* snapshot = nullptr; ProcessSnapshotSanitized sanitized; std::vector<std::string> annotations_whitelist; + std::vector<std::pair<VMAddress, VMAddress>> memory_range_whitelist; if (info.sanitization_information_address) { SanitizationInformation sanitization_info; ProcessMemoryRange range; @@ -153,11 +154,14 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( return false; } - if (sanitization_info.annotations_whitelist_address && - !ReadAnnotationsWhitelist( + if (!ReadAnnotationsWhitelist( range, sanitization_info.annotations_whitelist_address, - &annotations_whitelist)) { + &annotations_whitelist) || + !ReadMemoryRangeWhitelist( + range, + sanitization_info.memory_range_whitelist_address, + &memory_range_whitelist)) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kSanitizationInitializationFailed); return false; @@ -167,6 +171,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( sanitization_info.annotations_whitelist_address ? &annotations_whitelist : nullptr, + &memory_range_whitelist, sanitization_info.target_module_address, sanitization_info.sanitize_stacks)) { Metrics::ExceptionCaptureResult( diff --git a/snapshot/sanitized/process_snapshot_sanitized.cc b/snapshot/sanitized/process_snapshot_sanitized.cc index c8d3f67d..ae689e50 100644 --- a/snapshot/sanitized/process_snapshot_sanitized.cc +++ b/snapshot/sanitized/process_snapshot_sanitized.cc @@ -85,6 +85,7 @@ ProcessSnapshotSanitized::~ProcessSnapshotSanitized() = default; bool ProcessSnapshotSanitized::Initialize( const ProcessSnapshot* snapshot, const std::vector<std::string>* annotations_whitelist, + const std::vector<std::pair<VMAddress, VMAddress>>* memory_range_whitelist, VMAddress target_module_address, bool sanitize_stacks) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); @@ -157,6 +158,8 @@ bool ProcessSnapshotSanitized::Initialize( } } + process_memory_.Initialize(snapshot_->Memory(), memory_range_whitelist); + INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -264,8 +267,7 @@ std::vector<const MemorySnapshot*> ProcessSnapshotSanitized::ExtraMemory() const ProcessMemory* ProcessSnapshotSanitized::Memory() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/263 - return nullptr; + return &process_memory_; } } // namespace crashpad diff --git a/snapshot/sanitized/process_snapshot_sanitized.h b/snapshot/sanitized/process_snapshot_sanitized.h index d11c8632..9ed23509 100644 --- a/snapshot/sanitized/process_snapshot_sanitized.h +++ b/snapshot/sanitized/process_snapshot_sanitized.h @@ -30,6 +30,7 @@ #include "util/misc/initialization_state_dcheck.h" #include "util/misc/range_set.h" #include "util/process/process_id.h" +#include "util/process/process_memory_sanitized.h" namespace crashpad { @@ -62,6 +63,8 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot { //! should be filtered entirely. Otherwise `true`. bool Initialize(const ProcessSnapshot* snapshot, const std::vector<std::string>* annotations_whitelist, + const std::vector<std::pair<VMAddress, VMAddress>>* + memory_range_whitelist, VMAddress target_module_address, bool sanitize_stacks); @@ -95,6 +98,7 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot { RangeSet address_ranges_; const ProcessSnapshot* snapshot_; + ProcessMemorySanitized process_memory_; const std::vector<std::string>* annotations_whitelist_; bool sanitize_stacks_; InitializationStateDcheck initialized_; diff --git a/snapshot/sanitized/process_snapshot_sanitized_test.cc b/snapshot/sanitized/process_snapshot_sanitized_test.cc index e01ff324..9bad86c5 100644 --- a/snapshot/sanitized/process_snapshot_sanitized_test.cc +++ b/snapshot/sanitized/process_snapshot_sanitized_test.cc @@ -145,6 +145,22 @@ void ExpectAnnotations(ProcessSnapshot* snapshot, bool sanitized) { } } +void ExpectProcessMemory(ProcessSnapshot* snapshot, + VMAddress whitelisted_byte, + bool sanitized) { + auto memory = snapshot->Memory(); + + char out; + EXPECT_TRUE(memory->Read(whitelisted_byte, 1, &out)); + + bool unwhitelisted_read = memory->Read(whitelisted_byte + 1, 1, &out); + if (sanitized) { + EXPECT_FALSE(unwhitelisted_read); + } else { + EXPECT_TRUE(unwhitelisted_read); + } +} + class StackSanitizationChecker : public MemorySnapshot::Delegate { public: StackSanitizationChecker() = default; @@ -251,20 +267,33 @@ class SanitizeTest : public MultiprocessExec { ExpectAnnotations(&snapshot, /* sanitized= */ false); ExpectStackData(&snapshot, addrs, /* sanitized= */ false); + ExpectProcessMemory(&snapshot, + addrs.string_address, + /* sanitized= */ false); std::vector<std::string> annotations_whitelist; annotations_whitelist.push_back(kWhitelistedAnnotationName); + std::vector<std::pair<VMAddress, VMAddress>> memory_ranges_whitelist; + memory_ranges_whitelist.push_back( + std::make_pair(addrs.string_address, addrs.string_address + 1)); + ProcessSnapshotSanitized sanitized; - ASSERT_TRUE(sanitized.Initialize( - &snapshot, &annotations_whitelist, addrs.module_address, true)); + ASSERT_TRUE(sanitized.Initialize(&snapshot, + &annotations_whitelist, + &memory_ranges_whitelist, + addrs.module_address, + true)); ExpectAnnotations(&sanitized, /* sanitized= */ true); ExpectStackData(&sanitized, addrs, /* sanitized= */ true); + ExpectProcessMemory(&sanitized, + addrs.string_address, + /* sanitized= */ true); ProcessSnapshotSanitized screened_snapshot; EXPECT_FALSE(screened_snapshot.Initialize( - &snapshot, nullptr, addrs.non_module_address, false)); + &snapshot, nullptr, nullptr, addrs.non_module_address, false)); } DISALLOW_COPY_AND_ASSIGN(SanitizeTest); diff --git a/snapshot/sanitized/sanitization_information.cc b/snapshot/sanitized/sanitization_information.cc index d97f706f..ff376a39 100644 --- a/snapshot/sanitized/sanitization_information.cc +++ b/snapshot/sanitized/sanitization_information.cc @@ -14,6 +14,8 @@ #include "snapshot/sanitized/sanitization_information.h" +#include <limits> + #include "client/annotation.h" namespace crashpad { @@ -59,4 +61,54 @@ bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory, memory, whitelist_address, whitelist); } +bool ReadMemoryRangeWhitelist( + const ProcessMemoryRange& memory, + VMAddress whitelist_address, + std::vector<std::pair<VMAddress, VMAddress>>* whitelist) { + whitelist->clear(); + if (!whitelist_address) { + return true; + } + + SanitizationMemoryRangeWhitelist list; + if (!memory.Read(whitelist_address, sizeof(list), &list)) { + LOG(ERROR) << "Failed to read memory range whitelist."; + return false; + } + + if (!list.size) { + return true; + } + + // An upper bound of entries that we never expect to see more than. + constexpr size_t kMaxListSize = 256; + if (list.size > kMaxListSize) { + LOG(ERROR) << "Whitelist exceeded maximum, size=" << list.size; + return false; + } + + SanitizationMemoryRangeWhitelist::Range ranges[list.size]; + if (!memory.Read(list.entries, sizeof(ranges), &ranges)) { + LOG(ERROR) << "Failed to read memory range whitelist entries."; + return false; + } + + const VMAddress vm_max = memory.Is64Bit() + ? std::numeric_limits<uint64_t>::max() + : std::numeric_limits<uint32_t>::max(); + std::vector<std::pair<VMAddress, VMAddress>> local_whitelist; + for (size_t i = 0; i < list.size; i++) { + if (ranges[i].base > vm_max || ranges[i].length > vm_max - ranges[i].base) { + LOG(ERROR) << "Invalid memory range whitelist entry base=" + << ranges[i].base << " length=" << ranges[i].length; + return false; + } + local_whitelist.emplace_back(ranges[i].base, + ranges[i].base + ranges[i].length); + } + + whitelist->swap(local_whitelist); + return true; +} + } // namespace crashpad diff --git a/snapshot/sanitized/sanitization_information.h b/snapshot/sanitized/sanitization_information.h index 6a6d9089..0717ba7f 100644 --- a/snapshot/sanitized/sanitization_information.h +++ b/snapshot/sanitized/sanitization_information.h @@ -18,6 +18,7 @@ #include <stdint.h> #include <string> +#include <utility> #include <vector> #include "util/misc/address_types.h" @@ -45,10 +46,29 @@ struct SanitizationInformation { //! if there is no target module. VMAddress target_module_address; + //! \brief The address in the client process' address space of a + //! a \a SanitizationMemoryRangeWhitelist, a list of whitelisted address + //! ranges allowed to be accessed by ProcessMemorySanitized. This value + //! is 0 if no memory is allowed to be read using ProcessMemorySanitized. + VMAddress memory_range_whitelist_address; + //! \brief Non-zero if stacks should be sanitized for possible PII. uint8_t sanitize_stacks; }; +//! \brief Describes a list of white listed memory ranges. +struct SanitizationMemoryRangeWhitelist { + //! \brief Describes a range of memory. + struct Range { + VMAddress base; + VMSize length; + }; + + //! \brief Address of an array of |size| elements of type Range. + VMAddress entries; + VMSize size; +}; + #pragma pack(pop) //! \brief Reads an annotations whitelist from another process. @@ -63,6 +83,19 @@ bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory, VMAddress whitelist_address, std::vector<std::string>* whitelist); +//! \brief Reads a memory range whitelist from another process. +//! +//! \param[in] memory A memory reader for the target process. +//! \param[in] whitelist_address The address in the target process' address +//! space of a nullptr terminated array of NUL-terminated strings. +//! \param[out] whitelist A list of whitelisted memory regions, valid only if +//! this function returns `true`. +//! \return `true` on success, `false` on failure with a message logged. +bool ReadMemoryRangeWhitelist( + const ProcessMemoryRange& memory, + VMAddress whitelist_address, + std::vector<std::pair<VMAddress, VMAddress>>* whitelist); + } // namespace crashpad #endif // CRASHPAD_SNAPSHOT_SANITIZED_SANITIZATION_INFORMATION_H_ From 8edbc7439b2bbe9f2a5df4774e4133e92542aa43 Mon Sep 17 00:00:00 2001 From: Mike Frysinger <vapier@chromium.org> Date: Thu, 15 Aug 2019 15:19:56 -0400 Subject: [PATCH 239/401] codereview.settings: stop forcing squashing There's no reason this needs to be forced on users. All other repos have dropped it, and git-cl itself will be dropping it. Bug: 993518 Change-Id: Iebbb3ba7c36c3eaa5620fd918ca9a55724740bea Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1756663 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mike Frysinger <vapier@chromium.org> --- codereview.settings | 1 - 1 file changed, 1 deletion(-) diff --git a/codereview.settings b/codereview.settings index d8630972..976f8e53 100644 --- a/codereview.settings +++ b/codereview.settings @@ -13,7 +13,6 @@ # limitations under the License. GERRIT_HOST: True -GERRIT_SQUASH_UPLOADS: True CODE_REVIEW_SERVER: https://chromium-review.googlesource.com/ VIEW_VC: https://chromium.googlesource.com/crashpad/crashpad/+/ PROJECT: crashpad From 64399c514ff21ad8f59409ebab9a5339ce8d293c Mon Sep 17 00:00:00 2001 From: Casey Dahlin <sadmac@google.com> Date: Tue, 13 Aug 2019 15:14:20 -0700 Subject: [PATCH 240/401] Implement Exception context for minidump Bug: crashpad:10 Change-Id: I90d72d813da11d25c1ed13a51daacec9b0ad4a0f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1753063 Commit-Queue: Casey Dahlin <sadmac@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/BUILD.gn | 2 + .../minidump/exception_snapshot_minidump.cc | 22 +- .../minidump/exception_snapshot_minidump.h | 4 + .../minidump/minidump_context_converter.cc | 275 ++++++++++++++++++ .../minidump/minidump_context_converter.h | 47 +++ .../minidump/process_snapshot_minidump.cc | 3 +- .../process_snapshot_minidump_test.cc | 121 +++++--- snapshot/minidump/thread_snapshot_minidump.cc | 255 +--------------- snapshot/minidump/thread_snapshot_minidump.h | 7 +- snapshot/snapshot.gyp | 2 + 10 files changed, 450 insertions(+), 288 deletions(-) create mode 100644 snapshot/minidump/minidump_context_converter.cc create mode 100644 snapshot/minidump/minidump_context_converter.h diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index ae5b9cef..1be71f39 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -42,6 +42,8 @@ static_library("snapshot") { "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", diff --git a/snapshot/minidump/exception_snapshot_minidump.cc b/snapshot/minidump/exception_snapshot_minidump.cc index 0852ed90..afd32828 100644 --- a/snapshot/minidump/exception_snapshot_minidump.cc +++ b/snapshot/minidump/exception_snapshot_minidump.cc @@ -22,16 +22,20 @@ namespace internal { ExceptionSnapshotMinidump::ExceptionSnapshotMinidump() : ExceptionSnapshot(), minidump_exception_stream_(), + context_(), exception_information_(), initialized_() {} ExceptionSnapshotMinidump::~ExceptionSnapshotMinidump() {} bool ExceptionSnapshotMinidump::Initialize(FileReaderInterface* file_reader, + CPUArchitecture arch, RVA minidump_exception_stream_rva) { DCHECK(initialized_.is_uninitialized()); initialized_.set_invalid(); + std::vector<unsigned char> minidump_context; + if (!file_reader->SeekSet(minidump_exception_stream_rva)) { return false; } @@ -48,14 +52,28 @@ bool ExceptionSnapshotMinidump::Initialize(FileReaderInterface* file_reader, minidump_exception_stream_.ExceptionRecord.ExceptionInformation[i]); } + if (!file_reader->SeekSet(minidump_exception_stream_.ThreadContext.Rva)) { + return false; + } + + minidump_context.resize(minidump_exception_stream_.ThreadContext.DataSize); + + if (!file_reader->ReadExactly(minidump_context.data(), + minidump_context.size())) { + return false; + } + + if (!context_.Initialize(arch, minidump_context)) { + return false; + } + initialized_.set_valid(); return true; } const CPUContext* ExceptionSnapshotMinidump::Context() const { DCHECK(initialized_.is_valid()); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return nullptr; + return context_.Get(); } uint64_t ExceptionSnapshotMinidump::ThreadID() const { diff --git a/snapshot/minidump/exception_snapshot_minidump.h b/snapshot/minidump/exception_snapshot_minidump.h index 8ce29f7c..62f834fe 100644 --- a/snapshot/minidump/exception_snapshot_minidump.h +++ b/snapshot/minidump/exception_snapshot_minidump.h @@ -21,6 +21,7 @@ #include "build/build_config.h" #include "snapshot/cpu_context.h" #include "snapshot/exception_snapshot.h" +#include "snapshot/minidump/minidump_context_converter.h" #include "util/file/file_reader.h" #include "util/misc/initialization_state.h" @@ -37,12 +38,14 @@ class ExceptionSnapshotMinidump final : public ExceptionSnapshot { //! //! \param[in] file_reader A file reader corresponding to a minidump file. //! The file reader must support seeking. + //! \param[in] arch The CPU architecture of this snapshot. //! \param[in] minidump_exception_stream_rva The file offset in \a file_reader //! at which the MINIDUMP_EXCEPTION_STREAM structure is located. //! //! \return `true` if the snapshot could be created, `false` otherwise with //! an appropriate message logged. bool Initialize(FileReaderInterface* file_reader, + CPUArchitecture arch, RVA minidump_exception_stream_rva); // ExceptionSnapshot: @@ -60,6 +63,7 @@ class ExceptionSnapshotMinidump final : public ExceptionSnapshot { private: MINIDUMP_EXCEPTION_STREAM minidump_exception_stream_; + MinidumpContextConverter context_; std::vector<uint64_t> exception_information_; InitializationState initialized_; diff --git a/snapshot/minidump/minidump_context_converter.cc b/snapshot/minidump/minidump_context_converter.cc new file mode 100644 index 00000000..0c840dea --- /dev/null +++ b/snapshot/minidump/minidump_context_converter.cc @@ -0,0 +1,275 @@ +// 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. + +#include "snapshot/minidump/minidump_context_converter.h" + +#include "base/stl_util.h" +#include "minidump/minidump_context.h" + +namespace crashpad { +namespace internal { + +MinidumpContextConverter::MinidumpContextConverter() : initialized_() { + context_.architecture = CPUArchitecture::kCPUArchitectureUnknown; +} + +bool MinidumpContextConverter::Initialize( + CPUArchitecture arch, + const std::vector<unsigned char>& minidump_context) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + if (minidump_context.size() == 0) { + // Thread has no context. + context_.architecture = CPUArchitecture::kCPUArchitectureUnknown; + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; + } + + context_.architecture = arch; + + if (context_.architecture == CPUArchitecture::kCPUArchitectureX86) { + context_memory_.resize(sizeof(CPUContextX86)); + context_.x86 = reinterpret_cast<CPUContextX86*>(context_memory_.data()); + const MinidumpContextX86* src = + reinterpret_cast<const MinidumpContextX86*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextX86)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextX86)) { + return false; + } + + if (src->context_flags & kMinidumpContextX86Extended) { + context_.x86->fxsave = src->fxsave; + } else if (src->context_flags & kMinidumpContextX86FloatingPoint) { + CPUContextX86::FsaveToFxsave(src->fsave, &context_.x86->fxsave); + } + + context_.x86->eax = src->eax; + context_.x86->ebx = src->ebx; + context_.x86->ecx = src->ecx; + context_.x86->edx = src->edx; + context_.x86->edi = src->edi; + context_.x86->esi = src->esi; + context_.x86->ebp = src->ebp; + context_.x86->esp = src->esp; + context_.x86->eip = src->eip; + context_.x86->eflags = src->eflags; + context_.x86->cs = static_cast<uint16_t>(src->cs); + context_.x86->ds = static_cast<uint16_t>(src->ds); + context_.x86->es = static_cast<uint16_t>(src->es); + context_.x86->fs = static_cast<uint16_t>(src->fs); + context_.x86->gs = static_cast<uint16_t>(src->gs); + context_.x86->ss = static_cast<uint16_t>(src->ss); + context_.x86->dr0 = src->dr0; + context_.x86->dr1 = src->dr1; + context_.x86->dr2 = src->dr2; + context_.x86->dr3 = src->dr3; + context_.x86->dr6 = src->dr6; + context_.x86->dr7 = src->dr7; + + // Minidump passes no value for dr4/5. Our output context has space for + // them. According to spec they're obsolete, but when present read as + // aliases for dr6/7, so we'll do this. + context_.x86->dr4 = src->dr6; + context_.x86->dr5 = src->dr7; + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureX86_64) { + context_memory_.resize(sizeof(CPUContextX86_64)); + context_.x86_64 = + reinterpret_cast<CPUContextX86_64*>(context_memory_.data()); + const MinidumpContextAMD64* src = + reinterpret_cast<const MinidumpContextAMD64*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextAMD64)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextAMD64)) { + return false; + } + + context_.x86_64->fxsave = src->fxsave; + context_.x86_64->cs = src->cs; + context_.x86_64->fs = src->fs; + context_.x86_64->gs = src->gs; + context_.x86_64->rflags = src->eflags; + context_.x86_64->dr0 = src->dr0; + context_.x86_64->dr1 = src->dr1; + context_.x86_64->dr2 = src->dr2; + context_.x86_64->dr3 = src->dr3; + context_.x86_64->dr6 = src->dr6; + context_.x86_64->dr7 = src->dr7; + context_.x86_64->rax = src->rax; + context_.x86_64->rcx = src->rcx; + context_.x86_64->rdx = src->rdx; + context_.x86_64->rbx = src->rbx; + context_.x86_64->rsp = src->rsp; + context_.x86_64->rbp = src->rbp; + context_.x86_64->rsi = src->rsi; + context_.x86_64->rdi = src->rdi; + context_.x86_64->r8 = src->r8; + context_.x86_64->r9 = src->r9; + context_.x86_64->r10 = src->r10; + context_.x86_64->r11 = src->r11; + context_.x86_64->r12 = src->r12; + context_.x86_64->r13 = src->r13; + context_.x86_64->r14 = src->r14; + context_.x86_64->r15 = src->r15; + context_.x86_64->rip = src->rip; + + // See comments on x86 above. + context_.x86_64->dr4 = src->dr6; + context_.x86_64->dr5 = src->dr7; + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM) { + context_memory_.resize(sizeof(CPUContextARM)); + context_.arm = reinterpret_cast<CPUContextARM*>(context_memory_.data()); + const MinidumpContextARM* src = + reinterpret_cast<const MinidumpContextARM*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextARM)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextARM)) { + return false; + } + + for (size_t i = 0; i < base::size(src->regs); i++) { + context_.arm->regs[i] = src->regs[i]; + } + + context_.arm->fp = src->fp; + context_.arm->ip = src->ip; + context_.arm->sp = src->sp; + context_.arm->lr = src->lr; + context_.arm->pc = src->pc; + context_.arm->cpsr = src->cpsr; + context_.arm->vfp_regs.fpscr = src->fpscr; + + for (size_t i = 0; i < base::size(src->vfp); i++) { + context_.arm->vfp_regs.vfp[i] = src->vfp[i]; + } + + context_.arm->have_fpa_regs = false; + context_.arm->have_vfp_regs = + !!(src->context_flags & kMinidumpContextARMVFP); + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM64) { + context_memory_.resize(sizeof(CPUContextARM64)); + context_.arm64 = reinterpret_cast<CPUContextARM64*>(context_memory_.data()); + const MinidumpContextARM64* src = + reinterpret_cast<const MinidumpContextARM64*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextARM64)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextARM64)) { + return false; + } + + for (size_t i = 0; i < base::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++) { + context_.arm64->fpsimd[i] = src->fpsimd[i]; + } + + context_.arm64->sp = src->sp; + context_.arm64->pc = src->pc; + context_.arm64->fpcr = src->fpcr; + context_.arm64->fpsr = src->fpsr; + context_.arm64->spsr = src->cpsr; + } else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPSEL) { + context_memory_.resize(sizeof(CPUContextMIPS)); + context_.mipsel = reinterpret_cast<CPUContextMIPS*>(context_memory_.data()); + const MinidumpContextMIPS* src = + reinterpret_cast<const MinidumpContextMIPS*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextMIPS)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextMIPS)) { + return false; + } + + for (size_t i = 0; i < base::size(src->regs); i++) { + context_.mipsel->regs[i] = src->regs[i]; + } + + context_.mipsel->mdhi = static_cast<uint32_t>(src->mdhi); + context_.mipsel->mdlo = static_cast<uint32_t>(src->mdlo); + context_.mipsel->dsp_control = src->dsp_control; + + for (size_t i = 0; i < base::size(src->hi); i++) { + context_.mipsel->hi[i] = src->hi[i]; + context_.mipsel->lo[i] = src->lo[i]; + } + + context_.mipsel->cp0_epc = static_cast<uint32_t>(src->epc); + context_.mipsel->cp0_badvaddr = static_cast<uint32_t>(src->badvaddr); + context_.mipsel->cp0_status = src->status; + context_.mipsel->cp0_cause = src->cause; + context_.mipsel->fpcsr = src->fpcsr; + context_.mipsel->fir = src->fir; + + memcpy(&context_.mipsel->fpregs, &src->fpregs, sizeof(src->fpregs)); + } else if (context_.architecture == + CPUArchitecture::kCPUArchitectureMIPS64EL) { + context_memory_.resize(sizeof(CPUContextMIPS64)); + context_.mips64 = + reinterpret_cast<CPUContextMIPS64*>(context_memory_.data()); + const MinidumpContextMIPS64* src = + reinterpret_cast<const MinidumpContextMIPS64*>(minidump_context.data()); + if (minidump_context.size() < sizeof(MinidumpContextMIPS64)) { + return false; + } + + if (!(src->context_flags & kMinidumpContextMIPS64)) { + return false; + } + + for (size_t i = 0; i < base::size(src->regs); i++) { + context_.mips64->regs[i] = src->regs[i]; + } + + context_.mips64->mdhi = src->mdhi; + context_.mips64->mdlo = src->mdlo; + context_.mips64->dsp_control = src->dsp_control; + + for (size_t i = 0; i < base::size(src->hi); i++) { + context_.mips64->hi[i] = src->hi[i]; + context_.mips64->lo[i] = src->lo[i]; + } + + context_.mips64->cp0_epc = src->epc; + context_.mips64->cp0_badvaddr = src->badvaddr; + context_.mips64->cp0_status = src->status; + context_.mips64->cp0_cause = src->cause; + context_.mips64->fpcsr = src->fpcsr; + context_.mips64->fir = src->fir; + + memcpy(&context_.mips64->fpregs, &src->fpregs, sizeof(src->fpregs)); + } else { + // Architecture is listed as "unknown". + DLOG(ERROR) << "Unknown architecture"; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/minidump/minidump_context_converter.h b/snapshot/minidump/minidump_context_converter.h new file mode 100644 index 00000000..48e36c1f --- /dev/null +++ b/snapshot/minidump/minidump_context_converter.h @@ -0,0 +1,47 @@ +// 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_SNAPSHOT_MINIDUMP_MINIDUMP_CONTEXT_CONVERTER_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_CONTEXT_CONVERTER_H_ + +#include <vector> + +#include "snapshot/cpu_context.h" +#include "util/misc/initialization_state.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { + +class MinidumpContextConverter { + public: + MinidumpContextConverter(); + + bool Initialize(CPUArchitecture arch, + const std::vector<unsigned char>& minidump_context); + const CPUContext* Get() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return &context_; + } + + private: + CPUContext context_; + std::vector<unsigned char> context_memory_; + InitializationStateDcheck initialized_; +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_CONTEXT_CONVERTER_H_ diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index ae8c63e7..6a032f90 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -596,7 +596,8 @@ bool ProcessSnapshotMinidump::InitializeExceptionSnapshot() { return false; } - if (!exception_snapshot_.Initialize(file_reader_, stream_it->second->Rva)) { + if (!exception_snapshot_.Initialize( + file_reader_, arch_, stream_it->second->Rva)) { return false; } diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index b3e122e0..9794979c 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -47,6 +47,43 @@ class ReadToVector : public crashpad::MemorySnapshot::Delegate { } }; +MinidumpContextARM64 GetArm64MinidumpContext() { + MinidumpContextARM64 minidump_context; + + minidump_context.context_flags = kMinidumpContextARM64Full; + + minidump_context.cpsr = 0; + + for (int i = 0; i < 29; i++) { + minidump_context.regs[i] = i + 1; + } + + minidump_context.fp = 30; + minidump_context.lr = 31; + minidump_context.sp = 32; + minidump_context.pc = 33; + + for (int i = 0; i < 32; i++) { + minidump_context.fpsimd[i].lo = i * 2 + 34; + minidump_context.fpsimd[i].hi = i * 2 + 35; + } + + minidump_context.fpcr = 98; + minidump_context.fpsr = 99; + + for (int i = 0; i < 8; i++) { + minidump_context.bcr[i] = i * 2 + 100; + minidump_context.bvr[i] = i * 2 + 101; + } + + for (int i = 0; i < 2; i++) { + minidump_context.wcr[i] = i * 2 + 115; + minidump_context.wvr[i] = i * 2 + 116; + } + + return minidump_context; +} + TEST(ProcessSnapshotMinidump, EmptyFile) { StringFile string_file; ProcessSnapshotMinidump process_snapshot; @@ -799,38 +836,7 @@ TEST(ProcessSnapshotMinidump, ThreadContextARM64) { minidump_thread.ThreadId = 42; minidump_thread.Teb = 24; - MinidumpContextARM64 minidump_context; - - minidump_context.context_flags = kMinidumpContextARM64Full; - - minidump_context.cpsr = 0; - - for (int i = 0; i < 29; i++) { - minidump_context.regs[i] = i + 1; - } - - minidump_context.fp = 30; - minidump_context.lr = 31; - minidump_context.sp = 32; - minidump_context.pc = 33; - - for (int i = 0; i < 32; i++) { - minidump_context.fpsimd[i].lo = i * 2 + 34; - minidump_context.fpsimd[i].hi = i * 2 + 35; - } - - minidump_context.fpcr = 98; - minidump_context.fpsr = 99; - - for (int i = 0; i < 8; i++) { - minidump_context.bcr[i] = i * 2 + 100; - minidump_context.bvr[i] = i * 2 + 101; - } - - for (int i = 0; i < 2; i++) { - minidump_context.wcr[i] = i * 2 + 115; - minidump_context.wvr[i] = i * 2 + 116; - } + MinidumpContextARM64 minidump_context = GetArm64MinidumpContext(); minidump_thread.ThreadContext.DataSize = sizeof(minidump_context); minidump_thread.ThreadContext.Rva = static_cast<RVA>(string_file.SeekGet()); @@ -1314,10 +1320,35 @@ TEST(ProcessSnapshotMinidump, Exception) { minidump_exception.ExceptionInformation[0] = 51; minidump_exception.ExceptionInformation[1] = 62; + MINIDUMP_SYSTEM_INFO minidump_system_info = {}; + + minidump_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureARM64; + minidump_system_info.ProductType = kMinidumpOSTypeServer; + minidump_system_info.PlatformId = kMinidumpOSFuchsia; + minidump_system_info.CSDVersionRva = WriteString(&string_file, ""); + + MINIDUMP_DIRECTORY minidump_system_info_directory = {}; + minidump_system_info_directory.StreamType = kMinidumpStreamTypeSystemInfo; + minidump_system_info_directory.Location.DataSize = + sizeof(MINIDUMP_SYSTEM_INFO); + minidump_system_info_directory.Location.Rva = + static_cast<RVA>(string_file.SeekGet()); + + ASSERT_TRUE( + string_file.Write(&minidump_system_info, sizeof(minidump_system_info))); + MINIDUMP_EXCEPTION_STREAM minidump_exception_stream = {}; minidump_exception_stream.ThreadId = 5; minidump_exception_stream.ExceptionRecord = minidump_exception; + MinidumpContextARM64 minidump_context = GetArm64MinidumpContext(); + + minidump_exception_stream.ThreadContext.DataSize = sizeof(minidump_context); + minidump_exception_stream.ThreadContext.Rva = + static_cast<RVA>(string_file.SeekGet()); + + ASSERT_TRUE(string_file.Write(&minidump_context, sizeof(minidump_context))); + MINIDUMP_DIRECTORY minidump_exception_directory = {}; minidump_exception_directory.StreamType = kMinidumpStreamTypeException; minidump_exception_directory.Location.DataSize = @@ -1331,10 +1362,12 @@ TEST(ProcessSnapshotMinidump, Exception) { header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet()); ASSERT_TRUE(string_file.Write(&minidump_exception_directory, sizeof(minidump_exception_directory))); + ASSERT_TRUE(string_file.Write(&minidump_system_info_directory, + sizeof(minidump_system_info_directory))); header.Signature = MINIDUMP_SIGNATURE; header.Version = MINIDUMP_VERSION; - header.NumberOfStreams = 1; + header.NumberOfStreams = 2; EXPECT_TRUE(string_file.SeekSet(0)); EXPECT_TRUE(string_file.Write(&header, sizeof(header))); @@ -1352,6 +1385,28 @@ TEST(ProcessSnapshotMinidump, Exception) { EXPECT_EQ(codes.size(), 2UL); EXPECT_EQ(codes[0], 51UL); EXPECT_EQ(codes[1], 62UL); + + const CPUContext* ctx_generic = s->Context(); + + ASSERT_EQ(ctx_generic->architecture, CPUArchitecture::kCPUArchitectureARM64); + + const CPUContextARM64* ctx = ctx_generic->arm64; + + EXPECT_EQ(ctx->spsr, 0UL); + + for (unsigned int i = 0; i < 31; i++) { + EXPECT_EQ(ctx->regs[i], i + 1); + } + + EXPECT_EQ(ctx->sp, 32UL); + EXPECT_EQ(ctx->pc, 33UL); + EXPECT_EQ(ctx->fpcr, 98UL); + EXPECT_EQ(ctx->fpsr, 99UL); + + for (unsigned int i = 0; i < 32; i++) { + EXPECT_EQ(ctx->fpsimd[i].lo, i * 2 + 34); + EXPECT_EQ(ctx->fpsimd[i].hi, i * 2 + 35); + } } TEST(ProcessSnapshotMinidump, NoExceptionInMinidump) { diff --git a/snapshot/minidump/thread_snapshot_minidump.cc b/snapshot/minidump/thread_snapshot_minidump.cc index 30b2d710..8a5a2fd6 100644 --- a/snapshot/minidump/thread_snapshot_minidump.cc +++ b/snapshot/minidump/thread_snapshot_minidump.cc @@ -27,13 +27,10 @@ ThreadSnapshotMinidump::ThreadSnapshotMinidump() : ThreadSnapshot(), minidump_thread_(), context_(), - context_memory_(), stack_(), - initialized_() { -} + initialized_() {} -ThreadSnapshotMinidump::~ThreadSnapshotMinidump() { -} +ThreadSnapshotMinidump::~ThreadSnapshotMinidump() {} bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, RVA minidump_thread_rva, @@ -41,8 +38,6 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, INITIALIZATION_STATE_SET_INITIALIZING(initialized_); std::vector<unsigned char> minidump_context; - context_.architecture = arch; - if (!file_reader->SeekSet(minidump_thread_rva)) { return false; } @@ -62,12 +57,12 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, return false; } - if (!InitializeContext(minidump_context)) { + if (!context_.Initialize(arch, minidump_context)) { return false; } - RVA stack_info_location = minidump_thread_rva + - offsetof(MINIDUMP_THREAD, Stack); + RVA stack_info_location = + minidump_thread_rva + offsetof(MINIDUMP_THREAD, Stack); if (!stack_.Initialize(file_reader, stack_info_location)) { return false; @@ -77,244 +72,6 @@ bool ThreadSnapshotMinidump::Initialize(FileReaderInterface* file_reader, return true; } -bool ThreadSnapshotMinidump::InitializeContext( - const std::vector<unsigned char>& minidump_context) { - if (minidump_context.size() == 0) { - // Thread has no context. - context_.architecture = CPUArchitecture::kCPUArchitectureUnknown; - return true; - } - - if (context_.architecture == CPUArchitecture::kCPUArchitectureX86) { - context_memory_.resize(sizeof(CPUContextX86)); - context_.x86 = reinterpret_cast<CPUContextX86*>(context_memory_.data()); - const MinidumpContextX86* src = - reinterpret_cast<const MinidumpContextX86*>(minidump_context.data()); - if (minidump_context.size() < sizeof(MinidumpContextX86)) { - return false; - } - - if (!(src->context_flags & kMinidumpContextX86)) { - return false; - } - - if (src->context_flags & kMinidumpContextX86Extended) { - context_.x86->fxsave = src->fxsave; - } else if (src->context_flags & kMinidumpContextX86FloatingPoint) { - CPUContextX86::FsaveToFxsave(src->fsave, &context_.x86->fxsave); - } - - context_.x86->eax = src->eax; - context_.x86->ebx = src->ebx; - context_.x86->ecx = src->ecx; - context_.x86->edx = src->edx; - context_.x86->edi = src->edi; - context_.x86->esi = src->esi; - context_.x86->ebp = src->ebp; - context_.x86->esp = src->esp; - context_.x86->eip = src->eip; - context_.x86->eflags = src->eflags; - context_.x86->cs = static_cast<uint16_t>(src->cs); - context_.x86->ds = static_cast<uint16_t>(src->ds); - context_.x86->es = static_cast<uint16_t>(src->es); - context_.x86->fs = static_cast<uint16_t>(src->fs); - context_.x86->gs = static_cast<uint16_t>(src->gs); - context_.x86->ss = static_cast<uint16_t>(src->ss); - context_.x86->dr0 = src->dr0; - context_.x86->dr1 = src->dr1; - context_.x86->dr2 = src->dr2; - context_.x86->dr3 = src->dr3; - context_.x86->dr6 = src->dr6; - context_.x86->dr7 = src->dr7; - - // Minidump passes no value for dr4/5. Our output context has space for - // them. According to spec they're obsolete, but when present read as - // aliases for dr6/7, so we'll do this. - context_.x86->dr4 = src->dr6; - context_.x86->dr5 = src->dr7; - } else if (context_.architecture == CPUArchitecture::kCPUArchitectureX86_64) { - context_memory_.resize(sizeof(CPUContextX86_64)); - context_.x86_64 = - reinterpret_cast<CPUContextX86_64*>(context_memory_.data()); - const MinidumpContextAMD64* src = - reinterpret_cast<const MinidumpContextAMD64*>(minidump_context.data()); - if (minidump_context.size() < sizeof(MinidumpContextAMD64)) { - return false; - } - - if (!(src->context_flags & kMinidumpContextAMD64)) { - return false; - } - - context_.x86_64->fxsave = src->fxsave; - context_.x86_64->cs = src->cs; - context_.x86_64->fs = src->fs; - context_.x86_64->gs = src->gs; - context_.x86_64->rflags = src->eflags; - context_.x86_64->dr0 = src->dr0; - context_.x86_64->dr1 = src->dr1; - context_.x86_64->dr2 = src->dr2; - context_.x86_64->dr3 = src->dr3; - context_.x86_64->dr6 = src->dr6; - context_.x86_64->dr7 = src->dr7; - context_.x86_64->rax = src->rax; - context_.x86_64->rcx = src->rcx; - context_.x86_64->rdx = src->rdx; - context_.x86_64->rbx = src->rbx; - context_.x86_64->rsp = src->rsp; - context_.x86_64->rbp = src->rbp; - context_.x86_64->rsi = src->rsi; - context_.x86_64->rdi = src->rdi; - context_.x86_64->r8 = src->r8; - context_.x86_64->r9 = src->r9; - context_.x86_64->r10 = src->r10; - context_.x86_64->r11 = src->r11; - context_.x86_64->r12 = src->r12; - context_.x86_64->r13 = src->r13; - context_.x86_64->r14 = src->r14; - context_.x86_64->r15 = src->r15; - context_.x86_64->rip = src->rip; - - // See comments on x86 above. - context_.x86_64->dr4 = src->dr6; - context_.x86_64->dr5 = src->dr7; - } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM) { - context_memory_.resize(sizeof(CPUContextARM)); - context_.arm = reinterpret_cast<CPUContextARM*>(context_memory_.data()); - const MinidumpContextARM* src = - reinterpret_cast<const MinidumpContextARM*>(minidump_context.data()); - if (minidump_context.size() < sizeof(MinidumpContextARM)) { - return false; - } - - if (!(src->context_flags & kMinidumpContextARM)) { - return false; - } - - for (size_t i = 0; i < base::size(src->regs); i++) { - context_.arm->regs[i] = src->regs[i]; - } - - context_.arm->fp = src->fp; - context_.arm->ip = src->ip; - context_.arm->sp = src->sp; - context_.arm->lr = src->lr; - context_.arm->pc = src->pc; - context_.arm->cpsr = src->cpsr; - context_.arm->vfp_regs.fpscr = src->fpscr; - - for (size_t i = 0; i < base::size(src->vfp); i++) { - context_.arm->vfp_regs.vfp[i] = src->vfp[i]; - } - - context_.arm->have_fpa_regs = false; - context_.arm->have_vfp_regs = - !!(src->context_flags & kMinidumpContextARMVFP); - } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM64) { - context_memory_.resize(sizeof(CPUContextARM64)); - context_.arm64= reinterpret_cast<CPUContextARM64*>(context_memory_.data()); - const MinidumpContextARM64* src = - reinterpret_cast<const MinidumpContextARM64*>(minidump_context.data()); - if (minidump_context.size() < sizeof(MinidumpContextARM64)) { - return false; - } - - if (!(src->context_flags & kMinidumpContextARM64)) { - return false; - } - - for (size_t i = 0; i < base::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++) { - context_.arm64->fpsimd[i] = src->fpsimd[i]; - } - - context_.arm64->sp = src->sp; - context_.arm64->pc = src->pc; - context_.arm64->fpcr = src->fpcr; - context_.arm64->fpsr = src->fpsr; - context_.arm64->spsr = src->cpsr; - } else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPSEL) { - context_memory_.resize(sizeof(CPUContextMIPS)); - context_.mipsel = reinterpret_cast<CPUContextMIPS*>(context_memory_.data()); - const MinidumpContextMIPS* src = - reinterpret_cast<const MinidumpContextMIPS*>(minidump_context.data()); - if (minidump_context.size() < sizeof(MinidumpContextMIPS)) { - return false; - } - - if (!(src->context_flags & kMinidumpContextMIPS)) { - return false; - } - - for (size_t i = 0; i < base::size(src->regs); i++) { - context_.mipsel->regs[i] = src->regs[i]; - } - - context_.mipsel->mdhi = static_cast<uint32_t>(src->mdhi); - context_.mipsel->mdlo = static_cast<uint32_t>(src->mdlo); - context_.mipsel->dsp_control = src->dsp_control; - - for (size_t i = 0; i < base::size(src->hi); i++) { - context_.mipsel->hi[i] = src->hi[i]; - context_.mipsel->lo[i] = src->lo[i]; - } - - context_.mipsel->cp0_epc = static_cast<uint32_t>(src->epc); - context_.mipsel->cp0_badvaddr = static_cast<uint32_t>(src->badvaddr); - context_.mipsel->cp0_status = src->status; - context_.mipsel->cp0_cause = src->cause; - context_.mipsel->fpcsr = src->fpcsr; - context_.mipsel->fir = src->fir; - - memcpy(&context_.mipsel->fpregs, &src->fpregs, sizeof(src->fpregs)); - } else if (context_.architecture == - CPUArchitecture::kCPUArchitectureMIPS64EL) { - context_memory_.resize(sizeof(CPUContextMIPS64)); - context_.mips64 = - reinterpret_cast<CPUContextMIPS64*>(context_memory_.data()); - const MinidumpContextMIPS64* src = - reinterpret_cast<const MinidumpContextMIPS64*>(minidump_context.data()); - if (minidump_context.size() < sizeof(MinidumpContextMIPS64)) { - return false; - } - - if (!(src->context_flags & kMinidumpContextMIPS64)) { - return false; - } - - for (size_t i = 0; i < base::size(src->regs); i++) { - context_.mips64->regs[i] = src->regs[i]; - } - - context_.mips64->mdhi = src->mdhi; - context_.mips64->mdlo = src->mdlo; - context_.mips64->dsp_control = src->dsp_control; - - for (size_t i = 0; i < base::size(src->hi); i++) { - context_.mips64->hi[i] = src->hi[i]; - context_.mips64->lo[i] = src->lo[i]; - } - - context_.mips64->cp0_epc = src->epc; - context_.mips64->cp0_badvaddr = src->badvaddr; - context_.mips64->cp0_status = src->status; - context_.mips64->cp0_cause = src->cause; - context_.mips64->fpcsr = src->fpcsr; - context_.mips64->fir = src->fir; - - memcpy(&context_.mips64->fpregs, &src->fpregs, sizeof(src->fpregs)); - } - - // If we fell through, Architecture is listed as "unknown". - return true; -} - uint64_t ThreadSnapshotMinidump::ThreadID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return minidump_thread_.ThreadId; @@ -337,7 +94,7 @@ int ThreadSnapshotMinidump::Priority() const { const CPUContext* ThreadSnapshotMinidump::Context() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return &context_; + return context_.Get(); } const MemorySnapshot* ThreadSnapshotMinidump::Stack() const { diff --git a/snapshot/minidump/thread_snapshot_minidump.h b/snapshot/minidump/thread_snapshot_minidump.h index 43234ddb..262b8da6 100644 --- a/snapshot/minidump/thread_snapshot_minidump.h +++ b/snapshot/minidump/thread_snapshot_minidump.h @@ -20,6 +20,7 @@ #include "minidump/minidump_extensions.h" #include "snapshot/cpu_context.h" #include "snapshot/minidump/memory_snapshot_minidump.h" +#include "snapshot/minidump/minidump_context_converter.h" #include "snapshot/thread_snapshot.h" #include "util/file/file_reader.h" #include "util/misc/initialization_state_dcheck.h" @@ -44,7 +45,8 @@ class ThreadSnapshotMinidump : public ThreadSnapshot { //! //! \return `true` if the snapshot could be created, `false` otherwise with //! an appropriate message logged. - bool Initialize(FileReaderInterface* file_reader, RVA minidump_thread_rva, + bool Initialize(FileReaderInterface* file_reader, + RVA minidump_thread_rva, CPUArchitecture arch); const CPUContext* Context() const override; @@ -65,8 +67,7 @@ class ThreadSnapshotMinidump : public ThreadSnapshot { bool InitializeContext(const std::vector<unsigned char>& minidump_context); MINIDUMP_THREAD minidump_thread_; - CPUContext context_; - std::vector<unsigned char> context_memory_; + MinidumpContextConverter context_; MemorySnapshotMinidump stack_; InitializationStateDcheck initialized_; diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index c4b7d52e..788ea3d1 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -109,6 +109,8 @@ 'memory_snapshot_generic.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', From 6b5e30db285fe8160087d647d29b287c95b9931d Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Fri, 16 Aug 2019 08:56:52 -0700 Subject: [PATCH 241/401] Fix signed-unsigned-wchar build failure Fix a build failure introduced by a new error diagnostic (-Wsigned-unsigned-wchar) in clang that has been fixed in a newer version of gtest and revert commit a34bca8611b6263632a94d3d773df076c81d03dd which worked around it. Change-Id: Ibe332bf65215e4722fd962540f144c435f77b2fb Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1753067 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- DEPS | 2 +- third_party/gtest/BUILD.gn | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/DEPS b/DEPS index 20a0fabc..acb4a39d 100644 --- a/DEPS +++ b/DEPS @@ -24,7 +24,7 @@ deps = { '3e50219fc4503f461b2176a9976891b28d80f9ab', 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + - 'da10da05c262af0a9e8fa91789a272a3dec67655', + 'eb78ee170ac9eb21487f4d127720c060351fa8a2', 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + '8bee09f4a57807136593ddc906b0b213c21f9014', diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index 286a1d9e..c2058e23 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -267,17 +267,6 @@ if (crashpad_is_in_chromium) { config("gmock_private_config") { visibility = [ ":*" ] include_dirs = [ "gtest/googlemock" ] - if (crashpad_is_clang && (crashpad_is_linux || crashpad_is_fuchsia)) { - cflags_cc = [ - # This seems a bit questionable: - # https://github.com/google/googletest/blob/bf6df7eaee5cfaafe2655fab143f348eba98c9af/googlemock/include/gmock/internal/gmock-internal-utils.h#L109 - # and causes a warning/error on recent clangs (Linux/Fuchsia currently - # have this, other platforms don't yet). - # Temporarily disable this warning for building gmock tests until - # internal CL 263406158 lands and rolls. - "-Wno-signed-unsigned-wchar", - ] - } } config("gmock_public_config") { From efaebfc482b7a44161015ef7f6661aa4526b1c26 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Mon, 19 Aug 2019 10:15:58 -0700 Subject: [PATCH 242/401] fuchsia: Capture from SP (+slop) to stack base, rather than entire stack Stack mappings can be enormous for some processes dwarfing all other data and making the .dmp useless. It isn't useful to capture beyond the stack pointer, so grab only from the stack base to the stack pointer. In the default config (safestack enabled), this isn't a major problem. However, Chromium has safestack disabled, along with a large stack size, so dumps with many threads become very large. Bug: https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=6425 Bug: chromium:821951 Change-Id: Iebefc5fe43e3d1bc4d8b66c107d3ab8ae5b3f68b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1758702 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Francois Rousseau <frousseau@google.com> --- snapshot/fuchsia/process_reader_fuchsia.cc | 16 +++++++++++++++- snapshot/fuchsia/process_reader_fuchsia_test.cc | 3 ++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/snapshot/fuchsia/process_reader_fuchsia.cc b/snapshot/fuchsia/process_reader_fuchsia.cc index e3eaf752..ecad29a4 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.cc +++ b/snapshot/fuchsia/process_reader_fuchsia.cc @@ -61,8 +61,22 @@ void GetStackRegions( << "stack range is unexpectedly marked executable, continuing anyway"; } + // The stack covers [range_with_sp.base, range_with_sp.base + + // range_with_sp.size). The stack pointer (sp) can be anywhere in that range. + // It starts at the end of the range (range_with_sp.base + range_with_sp.size) + // and goes downwards until range_with_sp.base. Capture the part of the stack + // that is currently used: [sp, range_with_sp.base + range_with_sp.size). + + // Capture up to kExtraCaptureSize additional bytes of stack, but only if + // present in the region that was already found. + constexpr uint64_t kExtraCaptureSize = 128; + const uint64_t start_address = + std::max(sp >= kExtraCaptureSize ? sp - kExtraCaptureSize : sp, + range_with_sp.base); + const size_t region_size = + range_with_sp.size - (start_address - range_with_sp.base); stack_regions->push_back( - CheckedRange<zx_vaddr_t, size_t>(range_with_sp.base, range_with_sp.size)); + CheckedRange<zx_vaddr_t, size_t>(start_address, region_size)); // TODO(scottmg): https://crashpad.chromium.org/bug/196, once the retrievable // registers include FS and similar for ARM, retrieve the region for the diff --git a/snapshot/fuchsia/process_reader_fuchsia_test.cc b/snapshot/fuchsia/process_reader_fuchsia_test.cc index 369ec9a3..581fb4e4 100644 --- a/snapshot/fuchsia/process_reader_fuchsia_test.cc +++ b/snapshot/fuchsia/process_reader_fuchsia_test.cc @@ -174,7 +174,8 @@ class ThreadsChildTest : public MultiprocessExec { for (size_t i = 1; i < 6; ++i) { ASSERT_GT(threads[i].stack_regions.size(), 0u); - EXPECT_EQ(threads[i].stack_regions[0].size(), i * 4096u); + EXPECT_GT(threads[i].stack_regions[0].size(), 0u); + EXPECT_LE(threads[i].stack_regions[0].size(), i * 4096u); } } From ec56fc6a38f0e021ef2a970b39c7198b270184eb Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 19 Aug 2019 11:30:12 -0700 Subject: [PATCH 243/401] linux: add Get/SetHandlerSocket() These methods are used to connect additional clients to an existing handler process. Bug: crashpad:285 Change-Id: Iefa5b0d8f5fd7d4799140ff9a7c2f79ac65da738 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1759281 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client.h | 25 +++++++++++++++++++++++++ client/crashpad_client_linux.cc | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 3db1c9c1..56d738b7 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -24,6 +24,7 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "build/build_config.h" +#include "util/file/file_io.h" #include "util/misc/capture_context.h" #if defined(OS_MACOSX) @@ -116,6 +117,30 @@ class CrashpadClient { bool restartable, bool asynchronous_start); +#if defined(OS_ANDROID) || defined(OS_LINUX) || DOXYGEN + //! \brief Retrieve the socket and process ID for the handler. + //! + //! `StartHandler()` must have successfully been called before calling this + //! method. + //! + //! \param[out] sock The socket connected to the handler. + //! \param[out] pid The handler's process ID. + //! \return `true` on success. Otherwise `false` with a message logged. + static bool GetHandlerSocket(int* sock, pid_t* pid); + + //! \brief Sets the socket to a presumably-running Crashpad handler process + //! which was started with StartHandler(). + //! + //! This method installs a signal handler to request crash dumps on \a sock. + //! + //! \param[in] sock A socket connected to a Crashpad handler. + //! \param[in] pid The process ID of the handler, used to set the handler as + //! this process' ptracer. 0 indicates it is not necessary to set the + //! handler as this process' ptracer. -1 indicates that the handler's + //! process ID should be determined by communicating over the socket. + static bool SetHandlerSocket(ScopedFileHandle sock, pid_t pid); +#endif // OS_ANDROID || OS_LINUX || DOXYGEN + #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/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 008f8587..2e2ec30a 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -284,9 +284,19 @@ class RequestCrashDumpHandler : public SignalHandler { return false; } sock_to_handler_.reset(sock.release()); + handler_pid_ = pid; return Install(); } + bool GetHandlerSocket(int* sock, pid_t* pid) { + if (!sock_to_handler_.is_valid()) { + return false; + } + *sock = sock_to_handler_.get(); + *pid = handler_pid_; + return true; + } + void HandleCrashImpl() override { ExceptionHandlerProtocol::ClientInformation info = {}; info.exception_information_address = @@ -302,6 +312,7 @@ class RequestCrashDumpHandler : public SignalHandler { ~RequestCrashDumpHandler() = delete; ScopedFileHandle sock_to_handler_; + pid_t handler_pid_ = -1; DISALLOW_COPY_AND_ASSIGN(RequestCrashDumpHandler); }; @@ -343,6 +354,20 @@ bool CrashpadClient::StartHandler( return signal_handler->Initialize(std::move(client_sock), -1); } +#if defined(OS_ANDROID) || defined(OS_LINUX) +// static +bool CrashpadClient::GetHandlerSocket(int* sock, pid_t* pid) { + auto signal_handler = RequestCrashDumpHandler::Get(); + return signal_handler->GetHandlerSocket(sock, pid); +} + +// static +bool CrashpadClient::SetHandlerSocket(ScopedFileHandle sock, pid_t pid) { + auto signal_handler = RequestCrashDumpHandler::Get(); + return signal_handler->Initialize(std::move(sock), pid); +} +#endif // OS_ANDROID || OS_LINUX + #if defined(OS_ANDROID) // static From 3a6c6012ba2b9ed662872ccaf7d276d56240943b Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 16 Aug 2019 17:09:58 -0700 Subject: [PATCH 244/401] linux: override exception thread ID When a crash dump request is received over a socket, the message includes a stack address of the thread requesting the dump. This can be used to override the ExceptionInfo's thread ID which may be incorrect in the handler's PID namespace. Bug: crashpad:286 Change-Id: I053cf709c5eeefb73b31328f16a806510e1bd35d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1759280 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- handler/linux/crash_report_exception_handler.cc | 13 +++++++++---- snapshot/linux/process_snapshot_linux.cc | 7 ++++++- snapshot/linux/process_snapshot_linux.h | 7 ++++++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 1688df79..875afec3 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -95,13 +95,18 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( return false; } - if (requesting_thread_id && requesting_thread_stack_address) { - *requesting_thread_id = process_snapshot.FindThreadWithStackAddress( + pid_t local_requesting_thread_id = -1; + if (requesting_thread_stack_address) { + local_requesting_thread_id = process_snapshot.FindThreadWithStackAddress( requesting_thread_stack_address); } - if (!process_snapshot.InitializeException( - info.exception_information_address)) { + if (requesting_thread_id) { + *requesting_thread_id = local_requesting_thread_id; + } + + if (!process_snapshot.InitializeException(info.exception_information_address, + local_requesting_thread_id)) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kExceptionInitializationFailed); return false; diff --git a/snapshot/linux/process_snapshot_linux.cc b/snapshot/linux/process_snapshot_linux.cc index bada3a95..35f870ec 100644 --- a/snapshot/linux/process_snapshot_linux.cc +++ b/snapshot/linux/process_snapshot_linux.cc @@ -64,7 +64,8 @@ pid_t ProcessSnapshotLinux::FindThreadWithStackAddress( } bool ProcessSnapshotLinux::InitializeException( - LinuxVMAddress exception_info_address) { + LinuxVMAddress exception_info_address, + pid_t exception_thread_id) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); DCHECK(!exception_); @@ -75,6 +76,10 @@ bool ProcessSnapshotLinux::InitializeException( return false; } + if (exception_thread_id >= 0) { + info.thread_id = exception_thread_id; + } + exception_.reset(new internal::ExceptionSnapshotLinux()); if (!exception_->Initialize(&process_reader_, info.siginfo_address, diff --git a/snapshot/linux/process_snapshot_linux.h b/snapshot/linux/process_snapshot_linux.h index 705cb5f9..06b72aff 100644 --- a/snapshot/linux/process_snapshot_linux.h +++ b/snapshot/linux/process_snapshot_linux.h @@ -70,7 +70,12 @@ class ProcessSnapshotLinux final : public ProcessSnapshot { //! //! \param[in] exception_info The address of an ExceptionInformation in the //! target process' address space. - bool InitializeException(LinuxVMAddress exception_info); + //! \param[in] exception_thread_id The thread ID to assocaite the thread with. + //! Optional. If -1, the exception thread will be identified by the + //! ExceptionInformation struct which contains the thread ID in the target + //! process' namespace. + bool InitializeException(LinuxVMAddress exception_info, + pid_t exception_thread_id = -1); //! \brief Sets the value to be returned by ReportID(). //! From 726ab2a6553954ac3ade3b4f14272c58e7f3c85a Mon Sep 17 00:00:00 2001 From: Tim Zheng <timzheng@google.com> Date: Mon, 19 Aug 2019 15:43:02 -0700 Subject: [PATCH 245/401] Integrate Crashpad with Chrome OS This CL adds modification to Crashpad to integrate Crashpad reporting for Chrome on Chrome OS. Design doc: go/cros-crashpad BUG=chromium:944123 Change-Id: I22e2f2a93f32c2dc149c9c011fa8134cf6d5b74f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1707369 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client.h | 10 + client/crashpad_client_linux.cc | 25 +++ handler/handler_main.cc | 11 +- .../linux/crash_report_exception_handler.cc | 172 +++++++++++++++++- .../linux/crash_report_exception_handler.h | 5 + handler/linux/exception_handler_server.cc | 4 +- handler/linux/exception_handler_server.h | 4 + .../linux/exception_handler_server_test.cc | 2 + minidump/minidump_file_writer.cc | 2 +- util/file/file_io.h | 13 ++ util/file/file_io_posix.cc | 15 ++ util/file/file_writer.cc | 17 ++ util/file/file_writer.h | 16 ++ util/linux/exception_handler_protocol.h | 4 + util/misc/metrics.h | 3 + 15 files changed, 293 insertions(+), 10 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 56d738b7..36c9d1f8 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -588,6 +588,16 @@ class CrashpadClient { static void UseSystemDefaultHandler(); #endif +#if defined(OS_CHROMEOS) + //! \brief Sets a timestamp on the signal handler to be passed on to + //! crashpad_handler and then eventually Chrome OS's crash_reporter. + //! + //! \note This method is used by clients that use `StartHandler()` to start + //! a handler and not by clients that use any other handler starting + //! methods. + static void SetCrashLoopBefore(uint64_t crash_loop_before_time); +#endif + private: #if defined(OS_MACOSX) base::mac::ScopedMachSendRight exception_port_; diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 2e2ec30a..eb210a28 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -301,11 +301,20 @@ class RequestCrashDumpHandler : public SignalHandler { ExceptionHandlerProtocol::ClientInformation info = {}; info.exception_information_address = FromPointerCast<VMAddress>(&GetExceptionInfo()); +#if defined(OS_CHROMEOS) + info.crash_loop_before_time = crash_loop_before_time_; +#endif ExceptionHandlerClient client(sock_to_handler_.get(), true); client.RequestCrashDump(info); } +#if defined(OS_CHROMEOS) + void SetCrashLoopBefore(uint64_t crash_loop_before_time) { + crash_loop_before_time_ = crash_loop_before_time; + } +#endif + private: RequestCrashDumpHandler() = default; @@ -314,6 +323,14 @@ class RequestCrashDumpHandler : public SignalHandler { ScopedFileHandle sock_to_handler_; pid_t handler_pid_ = -1; +#if defined(OS_CHROMEOS) + // An optional UNIX timestamp passed to us from Chrome. + // This will pass to crashpad_handler and then to Chrome OS crash_reporter. + // This should really be a time_t, but it's basically an opaque value (we + // don't anything with it except pass it along). + uint64_t crash_loop_before_time_ = 0; +#endif + DISALLOW_COPY_AND_ASSIGN(RequestCrashDumpHandler); }; @@ -526,4 +543,12 @@ void CrashpadClient::SetFirstChanceExceptionHandler( SignalHandler::Get()->SetFirstChanceHandler(handler); } +#if defined(OS_CHROMEOS) +// static +void CrashpadClient::SetCrashLoopBefore(uint64_t crash_loop_before_time) { + auto request_crash_dump_handler = RequestCrashDumpHandler::Get(); + request_crash_dump_handler->SetCrashLoopBefore(crash_loop_before_time); +} +#endif + } // namespace crashpad diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 05a2e7b4..91e3436f 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -509,6 +509,12 @@ class ScopedStoppable { int HandlerMain(int argc, char* argv[], const UserStreamDataSources* user_stream_sources) { +#if defined(OS_CHROMEOS) + if (freopen("/var/log/chrome/chrome", "a", stderr) == nullptr) { + PLOG(ERROR) << "Failed to redirect stderr to /var/log/chrome/chrome"; + } +#endif + InstallCrashHandler(); CallMetricsRecordNormalExit metrics_record_normal_exit; @@ -900,8 +906,9 @@ int HandlerMain(int argc, info.exception_information_address = options.exception_information_address; info.sanitization_information_address = options.sanitization_information_address; - return exception_handler.HandleException(getppid(), info) ? EXIT_SUCCESS - : ExitFailure(); + return exception_handler.HandleException(getppid(), geteuid(), info) + ? EXIT_SUCCESS + : ExitFailure(); } #endif // OS_LINUX || OS_ANDROID diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 875afec3..ebba899c 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -29,6 +29,105 @@ #include "util/misc/tri_state.h" #include "util/misc/uuid.h" +#if defined(OS_CHROMEOS) +#include "handler/minidump_to_upload_parameters.h" +#include "snapshot/minidump/process_snapshot_minidump.h" +#include "util/posix/double_fork_and_exec.h" + +namespace { +// Returns the process name for a pid. +const std::string GetProcessNameFromPid(pid_t pid) { + // Symlink to process binary is at /proc/###/exe. + std::string link_path = "/proc/" + std::to_string(pid) + "/exe"; + + constexpr int kMaxSize = 4096; + std::unique_ptr<char[]> buf(new char[kMaxSize]); + ssize_t size = readlink(link_path.c_str(), buf.get(), kMaxSize); + std::string result; + if (size < 0) { + PLOG(ERROR) << "Failed to readlink " << link_path; + } else { + result.assign(buf.get(), size); + size_t last_slash_pos = result.rfind('/'); + if (last_slash_pos != std::string::npos) { + result = result.substr(last_slash_pos + 1); + } + } + return result; +} + +bool WriteAnnotationsAndMinidump( + const std::map<std::string, std::string>& parameters, + crashpad::MinidumpFileWriter& minidump, + crashpad::FileWriter& file_writer) { + for (const auto& kv : parameters) { + if (kv.first.find(':') != std::string::npos) { + LOG(ERROR) << "Annotation key cannot have ':' in it " << kv.first; + return false; + } + if (!file_writer.Write(kv.first.c_str(), strlen(kv.first.c_str()))) { + return false; + } + if (!file_writer.Write(":", 1)) { + return false; + } + size_t value_size = strlen(kv.second.c_str()); + std::string value_size_str = std::to_string(value_size); + if (!file_writer.Write(value_size_str.c_str(), value_size_str.size())) { + return false; + } + if (!file_writer.Write(":", 1)) { + return false; + } + if (!file_writer.Write(kv.second.c_str(), strlen(kv.second.c_str()))) { + return false; + } + } + + static constexpr char kMinidumpName[] = + "upload_file_minidump\"; filename=\"dump\":"; + if (!file_writer.Write(kMinidumpName, sizeof(kMinidumpName) - 1)) { + return false; + } + crashpad::FileOffset dump_size_start_offset = file_writer.Seek(0, SEEK_CUR); + if (dump_size_start_offset < 0) { + LOG(ERROR) << "Failed to get minidump size start offset"; + return false; + } + static constexpr char kMinidumpLengthFilling[] = "00000000000000000000:"; + if (!file_writer.Write(kMinidumpLengthFilling, + sizeof(kMinidumpLengthFilling) - 1)) { + return false; + } + crashpad::FileOffset dump_start_offset = file_writer.Seek(0, SEEK_CUR); + if (dump_start_offset < 0) { + LOG(ERROR) << "Failed to get minidump start offset"; + return false; + } + if (!minidump.WriteEverything(&file_writer)) { + return false; + } + crashpad::FileOffset dump_end_offset = file_writer.Seek(0, SEEK_CUR); + if (dump_end_offset < 0) { + LOG(ERROR) << "Failed to get minidump end offset"; + return false; + } + + size_t dump_data_size = dump_end_offset - dump_start_offset; + std::string dump_data_size_str = std::to_string(dump_data_size); + file_writer.Seek(dump_size_start_offset + strlen(kMinidumpLengthFilling) - 1 - + dump_data_size_str.size(), + SEEK_SET); + if (!file_writer.Write(dump_data_size_str.c_str(), + dump_data_size_str.size())) { + return false; + } + return true; +} + +} // namespace +#endif // defined(OS_CHROMEOS) + namespace crashpad { CrashReportExceptionHandler::CrashReportExceptionHandler( @@ -37,14 +136,18 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( const std::map<std::string, std::string>* process_annotations, const UserStreamDataSources* user_stream_data_sources) : database_(database), +#if !defined(OS_CHROMEOS) upload_thread_(upload_thread), +#endif process_annotations_(process_annotations), - user_stream_data_sources_(user_stream_data_sources) {} + user_stream_data_sources_(user_stream_data_sources) { +} CrashReportExceptionHandler::~CrashReportExceptionHandler() = default; bool CrashReportExceptionHandler::HandleException( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, @@ -60,6 +163,7 @@ bool CrashReportExceptionHandler::HandleException( return HandleExceptionWithConnection(&connection, info, + client_uid, requesting_thread_stack_address, requesting_thread_id, local_report_id); @@ -67,6 +171,7 @@ bool CrashReportExceptionHandler::HandleException( bool CrashReportExceptionHandler::HandleExceptionWithBroker( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, int broker_sock, UUID* local_report_id) { @@ -80,12 +185,13 @@ bool CrashReportExceptionHandler::HandleExceptionWithBroker( } return HandleExceptionWithConnection( - &client, info, 0, nullptr, local_report_id); + &client, info, client_uid, 0, nullptr, local_report_id); } bool CrashReportExceptionHandler::HandleExceptionWithConnection( PtraceConnection* connection, const ExceptionHandlerProtocol::ClientInformation& info, + uid_t client_uid, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, UUID* local_report_id) { @@ -131,6 +237,12 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( process_snapshot.AddAnnotation(p.first, p.second); } + UUID uuid; +#if defined(OS_CHROMEOS) + uuid.InitializeWithNew(); + process_snapshot.SetReportID(uuid); +#else + std::unique_ptr<CrashReportDatabase::NewReport> new_report; CrashReportDatabase::OperationStatus database_status = database_->PrepareNewCrashReport(&new_report); @@ -142,6 +254,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( } process_snapshot.SetReportID(new_report->ReportID()); +#endif ProcessSnapshot* snapshot = nullptr; ProcessSnapshotSanitized sanitized; @@ -193,6 +306,53 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( minidump.InitializeFromSnapshot(snapshot); AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump); +#if defined(OS_CHROMEOS) + FileWriter file_writer; + if (!file_writer.OpenMemfd(base::FilePath("/tmp/minidump"))) { + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kOpenMemfdFailed); + return false; + } + + std::map<std::string, std::string> parameters = + BreakpadHTTPFormParametersFromMinidump(snapshot); + // Used to differenciate between breakpad and crashpad while the switch is + // ramping up. + parameters.emplace("crash_library", "crashpad"); + + if (!WriteAnnotationsAndMinidump(parameters, minidump, file_writer)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kMinidumpWriteFailed); + return false; + } + + // CrOS uses crash_reporter instead of Crashpad to report crashes. + // crash_reporter needs to know the pid and uid of the crashing process. + std::vector<std::string> argv({"/sbin/crash_reporter"}); + + argv.push_back("--chrome_memfd=" + std::to_string(file_writer.fd())); + argv.push_back("--pid=" + std::to_string(*requesting_thread_id)); + argv.push_back("--uid=" + std::to_string(client_uid)); + std::string process_name = GetProcessNameFromPid(*requesting_thread_id); + argv.push_back("--exe=" + (process_name.empty() ? "chrome" : process_name)); + + if (info.crash_loop_before_time != 0) { + argv.push_back("--crash_loop_before=" + + std::to_string(info.crash_loop_before_time)); + } + + if (!DoubleForkAndExec(argv, + nullptr /* envp */, + file_writer.fd() /* preserve_fd */, + false /* use_path */, + nullptr /* child_function */)) { + LOG(ERROR) << "DoubleForkAndExec failed"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kFinishedWritingCrashReportFailed); + return false; + } + +#else + if (!minidump.WriteEverything(new_report->Writer())) { LOG(ERROR) << "WriteEverything failed"; Metrics::ExceptionCaptureResult( @@ -200,7 +360,6 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( return false; } - UUID uuid; database_status = database_->FinishedWritingCrashReport(std::move(new_report), &uuid); if (database_status != CrashReportDatabase::kNoError) { @@ -209,13 +368,14 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( Metrics::CaptureResult::kFinishedWritingCrashReportFailed); return false; } - if (local_report_id != nullptr) { - *local_report_id = uuid; - } if (upload_thread_) { upload_thread_->ReportPending(uuid); } +#endif + if (local_report_id != nullptr) { + *local_report_id = uuid; + } } Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess); diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index dba8b63a..ca527587 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -65,6 +65,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { // ExceptionHandlerServer::Delegate: bool HandleException(pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address = 0, pid_t* requesting_thread_id = nullptr, @@ -72,6 +73,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { bool HandleExceptionWithBroker( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, int broker_sock, UUID* local_report_id = nullptr) override; @@ -80,12 +82,15 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { bool HandleExceptionWithConnection( PtraceConnection* connection, const ExceptionHandlerProtocol::ClientInformation& info, + uid_t client_uid, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, UUID* local_report_id = nullptr); CrashReportDatabase* database_; // weak +#if !defined(OS_CHROMEOS) CrashReportUploadThread* upload_thread_; // weak +#endif const std::map<std::string, std::string>* process_annotations_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index ef03696a..7bb14f92 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -448,6 +448,7 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( bool multiple_clients) { pid_t client_process_id = creds.pid; pid_t requesting_thread_id = -1; + uid_t client_uid = creds.uid; switch ( strategy_decider_->ChooseStrategy(client_sock, multiple_clients, creds)) { @@ -469,6 +470,7 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( case PtraceStrategyDecider::Strategy::kDirectPtrace: { delegate_->HandleException(client_process_id, + client_uid, client_info, requesting_thread_stack_address, &requesting_thread_id); @@ -482,7 +484,7 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( case PtraceStrategyDecider::Strategy::kUseBroker: DCHECK(!multiple_clients); delegate_->HandleExceptionWithBroker( - client_process_id, client_info, client_sock); + client_process_id, client_uid, client_info, client_sock); break; } diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index b6251e14..48dcf07b 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -76,6 +76,7 @@ class ExceptionHandlerServer { //! \brief Called on receipt of a crash dump request from a client. //! //! \param[in] client_process_id The process ID of the crashing client. + //! \param[in] client_uid The user ID of the crashing client. //! \param[in] info Information on the client. //! \param[in] requesting_thread_stack_address Any address within the stack //! range for the the thread that sent the crash dump request. Optional. @@ -88,6 +89,7 @@ class ExceptionHandlerServer { //! \return `true` on success. `false` on failure with a message logged. virtual bool HandleException( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address = 0, pid_t* requesting_thread_id = nullptr, @@ -97,6 +99,7 @@ class ExceptionHandlerServer { //! crash that should be mediated by a PtraceBroker. //! //! \param[in] client_process_id The process ID of the crashing client. + //! \param[in] client_uid The uid of the crashing client. //! \param[in] info Information on the client. //! \param[in] broker_sock A socket connected to the PtraceBroker. //! \param[out] local_report_id The unique identifier for the report created @@ -104,6 +107,7 @@ class ExceptionHandlerServer { //! \return `true` on success. `false` on failure with a message logged. virtual bool HandleExceptionWithBroker( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, int broker_sock, UUID* local_report_id = nullptr) = 0; diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index ea10db35..45f19965 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -108,6 +108,7 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { } bool HandleException(pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id = nullptr, @@ -141,6 +142,7 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { bool HandleExceptionWithBroker( pid_t client_process_id, + uid_t client_uid, const ExceptionHandlerProtocol::ClientInformation& info, int broker_sock, UUID* local_report_id = nullptr) override { diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index 72265453..f29a6fae 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -232,7 +232,7 @@ bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) { // it as a valid minidump file. header_.Signature = MINIDUMP_SIGNATURE; - if (file_writer->Seek(start_offset, SEEK_SET) != 0) { + if (file_writer->Seek(start_offset, SEEK_SET) < 0) { return false; } diff --git a/util/file/file_io.h b/util/file/file_io.h index 797db682..7af47f85 100644 --- a/util/file/file_io.h +++ b/util/file/file_io.h @@ -398,6 +398,19 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, FileWriteMode mode, FilePermissions permissions); +#if defined(OS_CHROMEOS) +//! \brief Wraps memfd_create(), logging an error if the operation fails. +//! Unlike other file open operations, this doesn't set `O_CLOEXEC`. +//! +//! \return The newly opened FileHandle, or an invalid FileHandle on failure. +//! +//! \sa ScopedFileHandle +//! \sa LoggingOpenFileForRead +//! \sa LoggingOpenFileForWrite +//! \sa LoggingOpenFileForReadAndWrite +FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path); +#endif + //! \brief Wraps OpenFileForReadAndWrite(), logging an error if the operation //! fails. //! diff --git a/util/file/file_io_posix.cc b/util/file/file_io_posix.cc index f3116169..03fc262e 100644 --- a/util/file/file_io_posix.cc +++ b/util/file/file_io_posix.cc @@ -16,6 +16,7 @@ #include <fcntl.h> #include <sys/file.h> +#include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> @@ -98,6 +99,12 @@ FileHandle OpenFileForOutput(int rdwr_or_wronly, permissions == FilePermissions::kWorldReadable ? 0644 : 0600)); } +#if defined(OS_CHROMEOS) +FileHandle OpenMemFileForOutput(const base::FilePath& path) { + return HANDLE_EINTR(memfd_create(path.value().c_str(), 0)); +} +#endif + } // namespace namespace internal { @@ -149,6 +156,14 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, return fd; } +#if defined(OS_CHROMEOS) +FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path) { + FileHandle fd = OpenMemFileForOutput(path); + PLOG_IF(ERROR, fd < 0) << "memfd_create " << path.value(); + return fd; +} +#endif + FileHandle LoggingOpenFileForReadAndWrite(const base::FilePath& path, FileWriteMode mode, FilePermissions permissions) { diff --git a/util/file/file_writer.cc b/util/file/file_writer.cc index 13ac6cf5..5f922429 100644 --- a/util/file/file_writer.cc +++ b/util/file/file_writer.cc @@ -171,6 +171,23 @@ bool FileWriter::Open(const base::FilePath& path, return true; } +#if defined(OS_CHROMEOS) +bool FileWriter::OpenMemfd(const base::FilePath& path) { + CHECK(!file_.is_valid()); + file_.reset(LoggingOpenMemFileForWrite(path)); + if (!file_.is_valid()) { + return false; + } + + weak_file_handle_file_writer_.set_file_handle(file_.get()); + return true; +} + +int FileWriter::fd() { + return file_.get(); +} +#endif + void FileWriter::Close() { CHECK(file_.is_valid()); diff --git a/util/file/file_writer.h b/util/file/file_writer.h index ed261ec5..1f9a0203 100644 --- a/util/file/file_writer.h +++ b/util/file/file_writer.h @@ -131,6 +131,22 @@ class FileWriter : public FileWriterInterface { FileWriteMode write_mode, FilePermissions permissions); +#if defined(OS_CHROMEOS) + //! \brief Wraps LoggingOpenMemFileForWrite(). + //! + //! \return `true` if the operation succeeded, `false` if it failed, with an + //! error message logged. + //! + //! \note After a successful call, this method or Open() cannot be called + // again until after Close(). + bool OpenMemfd(const base::FilePath& path); + + //! \brief Returns the underlying file descriptor. + //! + //! \note This is used when this writes to a Memfd. + int fd(); +#endif + //! \brief Wraps CheckedCloseHandle(). //! //! \note It is only valid to call this method on an object that has had a diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index 7f4da266..85b2f23f 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -50,6 +50,10 @@ class ExceptionHandlerProtocol { //! \brief The address in the client's address space of a //! SanitizationInformation struct, or 0 if there is no such struct. VMAddress sanitization_information_address; + +#if defined(OS_CHROMEOS) + uint64_t crash_loop_before_time; +#endif }; //! \brief The signal used to indicate a crash dump is complete. diff --git a/util/misc/metrics.h b/util/misc/metrics.h index 8046497e..d9763812 100644 --- a/util/misc/metrics.h +++ b/util/misc/metrics.h @@ -139,6 +139,9 @@ class Metrics { //! \brief Sanitization caused this crash dump to be skipped. kSkippedDueToSanitization = 11, + //! \brief Failure to open a memfd caused this crash dump to be skipped. + kOpenMemfdFailed = 12, + //! \brief The number of values in this enumeration; not a valid value. kMaxValue }; From db6f51d3fca8009dbe3c04341fc3c91809895425 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Tue, 20 Aug 2019 16:52:06 -0700 Subject: [PATCH 246/401] fuchsia: Check results of Initialize() subcalls in ProcessReaderFuchsia From looking at some syzkaller logs, the earliest error seems to be [...ERROR memory_map_fuchsia.cc:47] zx_object_get_info ZX_INFO_PROCESS_MAPS: ZX_ERR_BAD_STATE (-20) which might be caused by a failure to suspend. That error causes ProcessReaderFuchsia's memory_map_ Initialize() to fail, but that was mistakenly being ignored. Later calls then fail as well. While we're here, also check a couple other Initialize()s that were sometimes triggering later on. Bug: https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=34598 Change-Id: I9f9d7315f504e6ec69308add20e2737ce5c5f644 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1763028 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- snapshot/fuchsia/process_reader_fuchsia.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/snapshot/fuchsia/process_reader_fuchsia.cc b/snapshot/fuchsia/process_reader_fuchsia.cc index ecad29a4..c8d101b9 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.cc +++ b/snapshot/fuchsia/process_reader_fuchsia.cc @@ -105,7 +105,9 @@ bool ProcessReaderFuchsia::Initialize(const zx::process& process) { process_memory_.reset(new ProcessMemoryFuchsia()); process_memory_->Initialize(*process_); - memory_map_.Initialize(*process_); + if (!memory_map_.Initialize(*process_)) { + return false; + } INITIALIZATION_STATE_SET_VALID(initialized_); return true; @@ -255,13 +257,15 @@ void ProcessReaderFuchsia::InitializeModules() { std::unique_ptr<ProcessMemoryRange> process_memory_range( new ProcessMemoryRange()); // TODO(scottmg): Could this be limited range? - process_memory_range->Initialize(process_memory_.get(), true); - process_memory_ranges_.push_back(std::move(process_memory_range)); + if (process_memory_range->Initialize(process_memory_.get(), true)) { + process_memory_ranges_.push_back(std::move(process_memory_range)); - reader->Initialize(*process_memory_ranges_.back(), base); - module.reader = reader.get(); - module_readers_.push_back(std::move(reader)); - modules_.push_back(module); + if (reader->Initialize(*process_memory_ranges_.back(), base)) { + module.reader = reader.get(); + module_readers_.push_back(std::move(reader)); + modules_.push_back(module); + } + } map = next; } From 50aa576622fdaba476ea6c308616605922c5bafa Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Tue, 27 Aug 2019 11:46:59 -0700 Subject: [PATCH 247/401] Disable implicit fallthrough warning for zlib https://logs.chromium.org/logs/crashpad/buildbucket/cr-buildbucket.appspot.com/8903960674082840512/+/steps/compile_with_ninja/0/stdout I don't understand how this lingered for so long as I can't see what changed. mini_chromium has had -Wimplicit-fallthough enabled for a long time (https://chromium-review.googlesource.com/899847), and zlib DEPS hasn't changed in a long time either (https://chromium-review.googlesource.com/438585). The most likely would presumably be that the compiler started not-ignoring the enabling of the warning? But that doesn't seem too likely either. Bug: crashpad:309 Change-Id: I57480cc3f669ef94d0234afaf980281b7ddf8c51 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1772205 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- DEPS | 2 +- build/BUILDCONFIG.gn | 1 + third_party/zlib/BUILD.gn | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/DEPS b/DEPS index acb4a39d..46c34240 100644 --- a/DEPS +++ b/DEPS @@ -33,7 +33,7 @@ deps = { '8048ece6c16c91acfe0d36d1d3cc0890ab6e945c', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '6ad086b2b6ed3b3169226ee9f311eb2332f332c2', + '5889767521eed1483b5858b12c54893f21d72fd0', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/build/BUILDCONFIG.gn b/build/BUILDCONFIG.gn index 95dc2771..bc531083 100644 --- a/build/BUILDCONFIG.gn +++ b/build/BUILDCONFIG.gn @@ -55,6 +55,7 @@ declare_args() { _default_configs = [ "//third_party/mini_chromium/mini_chromium/build:default", "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", + "//third_party/mini_chromium/mini_chromium/build:Wimplicit_fallthrough", ] if (crashpad_use_libfuzzer) { diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn index f84b8baf..3267b981 100644 --- a/third_party/zlib/BUILD.gn +++ b/third_party/zlib/BUILD.gn @@ -104,6 +104,10 @@ if (zlib_source == "external") { ] } + configs -= [ + "//third_party/mini_chromium/mini_chromium/build:Wimplicit_fallthrough", + ] + if (current_cpu == "x86" || current_cpu == "x64") { sources += [ "zlib/crc_folding.c", From 1c7023875b743eac1ef5bb98141cdd241b4964e0 Mon Sep 17 00:00:00 2001 From: "P.Y. Laligand" <pylaligand@google.com> Date: Tue, 27 Aug 2019 07:29:41 -0700 Subject: [PATCH 248/401] [build] //zircon/public/fidl --> //zircon/system/fidl Bug: fuchsia:35562 Change-Id: Ic50ae72b870fe8aa415539a93aae4eaa2647731a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1773124 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- third_party/fuchsia/BUILD.gn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index b7f69e61..fd145872 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -17,8 +17,8 @@ import("../../build/crashpad_buildconfig.gni") if (crashpad_is_in_fuchsia) { group("fuchsia") { public_deps = [ - "//zircon/public/fidl/fuchsia.mem", - "//zircon/public/fidl/fuchsia.sysinfo:fuchsia.sysinfo_c", + "//zircon/system/fidl/fuchsia.mem", + "//zircon/system/fidl/fuchsia.sysinfo:fuchsia.sysinfo_c", "//zircon/public/lib/fdio", "//zircon/public/lib/zx", ] From 7b5a55c3b1882be3e2db0190dfb114ee96219a39 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 27 Aug 2019 15:25:49 -0700 Subject: [PATCH 249/401] Move whitelist ownership to ProcessSnapshotSanitized Change-Id: Ie57117229520e52aeff83d0cbf95057690894e5b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1773772 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- handler/linux/crash_report_exception_handler.cc | 13 +++++++------ snapshot/sanitized/process_snapshot_sanitized.cc | 11 ++++++----- snapshot/sanitized/process_snapshot_sanitized.h | 15 ++++++++------- .../sanitized/process_snapshot_sanitized_test.cc | 13 +++++++------ 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index ebba899c..48ff724c 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -258,8 +258,6 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( ProcessSnapshot* snapshot = nullptr; ProcessSnapshotSanitized sanitized; - std::vector<std::string> annotations_whitelist; - std::vector<std::pair<VMAddress, VMAddress>> memory_range_whitelist; if (info.sanitization_information_address) { SanitizationInformation sanitization_info; ProcessMemoryRange range; @@ -272,14 +270,17 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( return false; } + auto annotations_whitelist = std::make_unique<std::vector<std::string>>(); + auto memory_range_whitelist = + std::make_unique<std::vector<std::pair<VMAddress, VMAddress>>>(); if (!ReadAnnotationsWhitelist( range, sanitization_info.annotations_whitelist_address, - &annotations_whitelist) || + annotations_whitelist.get()) || !ReadMemoryRangeWhitelist( range, sanitization_info.memory_range_whitelist_address, - &memory_range_whitelist)) { + memory_range_whitelist.get())) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kSanitizationInitializationFailed); return false; @@ -287,9 +288,9 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( if (!sanitized.Initialize(&process_snapshot, sanitization_info.annotations_whitelist_address - ? &annotations_whitelist + ? std::move(annotations_whitelist) : nullptr, - &memory_range_whitelist, + std::move(memory_range_whitelist), sanitization_info.target_module_address, sanitization_info.sanitize_stacks)) { Metrics::ExceptionCaptureResult( diff --git a/snapshot/sanitized/process_snapshot_sanitized.cc b/snapshot/sanitized/process_snapshot_sanitized.cc index ae689e50..722abace 100644 --- a/snapshot/sanitized/process_snapshot_sanitized.cc +++ b/snapshot/sanitized/process_snapshot_sanitized.cc @@ -84,13 +84,14 @@ ProcessSnapshotSanitized::~ProcessSnapshotSanitized() = default; bool ProcessSnapshotSanitized::Initialize( const ProcessSnapshot* snapshot, - const std::vector<std::string>* annotations_whitelist, - const std::vector<std::pair<VMAddress, VMAddress>>* memory_range_whitelist, + std::unique_ptr<const std::vector<std::string>> annotations_whitelist, + std::unique_ptr<const std::vector<std::pair<VMAddress, VMAddress>>> + memory_range_whitelist, VMAddress target_module_address, bool sanitize_stacks) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); snapshot_ = snapshot; - annotations_whitelist_ = annotations_whitelist; + annotations_whitelist_ = std::move(annotations_whitelist); sanitize_stacks_ = sanitize_stacks; if (target_module_address) { @@ -141,7 +142,7 @@ bool ProcessSnapshotSanitized::Initialize( if (annotations_whitelist_) { for (const auto module : snapshot_->Modules()) { modules_.emplace_back(std::make_unique<internal::ModuleSnapshotSanitized>( - module, annotations_whitelist_)); + module, annotations_whitelist_.get())); } } @@ -158,7 +159,7 @@ bool ProcessSnapshotSanitized::Initialize( } } - process_memory_.Initialize(snapshot_->Memory(), memory_range_whitelist); + process_memory_.Initialize(snapshot_->Memory(), memory_range_whitelist.get()); INITIALIZATION_STATE_SET_VALID(initialized_); return true; diff --git a/snapshot/sanitized/process_snapshot_sanitized.h b/snapshot/sanitized/process_snapshot_sanitized.h index 9ed23509..4e7e6d6a 100644 --- a/snapshot/sanitized/process_snapshot_sanitized.h +++ b/snapshot/sanitized/process_snapshot_sanitized.h @@ -61,12 +61,13 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot { //! internal::StackSnapshotSanitized. //! \return `false` if \a snapshot does not meet sanitization requirements and //! should be filtered entirely. Otherwise `true`. - bool Initialize(const ProcessSnapshot* snapshot, - const std::vector<std::string>* annotations_whitelist, - const std::vector<std::pair<VMAddress, VMAddress>>* - memory_range_whitelist, - VMAddress target_module_address, - bool sanitize_stacks); + bool Initialize( + const ProcessSnapshot* snapshot, + std::unique_ptr<const std::vector<std::string>> annotations_whitelist, + std::unique_ptr<const std::vector<std::pair<VMAddress, VMAddress>>> + memory_range_whitelist, + VMAddress target_module_address, + bool sanitize_stacks); // ProcessSnapshot: @@ -99,7 +100,7 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot { RangeSet address_ranges_; const ProcessSnapshot* snapshot_; ProcessMemorySanitized process_memory_; - const std::vector<std::string>* annotations_whitelist_; + std::unique_ptr<const std::vector<std::string>> annotations_whitelist_; bool sanitize_stacks_; InitializationStateDcheck initialized_; diff --git a/snapshot/sanitized/process_snapshot_sanitized_test.cc b/snapshot/sanitized/process_snapshot_sanitized_test.cc index 9bad86c5..5c5ff1a5 100644 --- a/snapshot/sanitized/process_snapshot_sanitized_test.cc +++ b/snapshot/sanitized/process_snapshot_sanitized_test.cc @@ -271,17 +271,18 @@ class SanitizeTest : public MultiprocessExec { addrs.string_address, /* sanitized= */ false); - std::vector<std::string> annotations_whitelist; - annotations_whitelist.push_back(kWhitelistedAnnotationName); + auto annotations_whitelist = std::make_unique<std::vector<std::string>>(); + annotations_whitelist->push_back(kWhitelistedAnnotationName); - std::vector<std::pair<VMAddress, VMAddress>> memory_ranges_whitelist; - memory_ranges_whitelist.push_back( + auto memory_ranges_whitelist = + std::make_unique<std::vector<std::pair<VMAddress, VMAddress>>>(); + memory_ranges_whitelist->push_back( std::make_pair(addrs.string_address, addrs.string_address + 1)); ProcessSnapshotSanitized sanitized; ASSERT_TRUE(sanitized.Initialize(&snapshot, - &annotations_whitelist, - &memory_ranges_whitelist, + std::move(annotations_whitelist), + std::move(memory_ranges_whitelist), addrs.module_address, true)); From 10a1d2d8774307f90d868b063e10165d82e68af3 Mon Sep 17 00:00:00 2001 From: "P.Y. Laligand" <pylaligand@google.com> Date: Thu, 29 Aug 2019 14:48:51 -0700 Subject: [PATCH 250/401] [fuchsia] Use the appropriate separator for FIDL library names. Bug: fuchsia:35562 Change-Id: If465af3d91c418b448f837b850e10e8d12f3281b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1776919 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- third_party/fuchsia/BUILD.gn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index fd145872..9c25b58d 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -17,8 +17,8 @@ import("../../build/crashpad_buildconfig.gni") if (crashpad_is_in_fuchsia) { group("fuchsia") { public_deps = [ - "//zircon/system/fidl/fuchsia.mem", - "//zircon/system/fidl/fuchsia.sysinfo:fuchsia.sysinfo_c", + "//zircon/system/fidl/fuchsia-mem", + "//zircon/system/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c", "//zircon/public/lib/fdio", "//zircon/public/lib/zx", ] From b71f61f8e31f75fb624fb280d4d80fb351e50f90 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 29 Aug 2019 16:43:39 -0700 Subject: [PATCH 251/401] fuchsia: Defer initialization of memory map This allows partial reading of the current process (e.g. modules or CrashpadInfo), even though the memory map read (and so thread retrieval) will fail if ProcessSnapshotFuchsia is used on the current process. This is a follow up to https://chromium.googlesource.com/crashpad/crashpad/+/db6f51d3fca8009dbe3c04341fc3c91809895425 which broke the CrashpadInfoClientOptions.* tests. Bug: fuchsia:34598 Change-Id: Ifa17b4dbefcd198ff67ecea91f946cfa2439ca4c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1776936 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- snapshot/fuchsia/process_reader_fuchsia.cc | 33 +++++++++++++++++--- snapshot/fuchsia/process_reader_fuchsia.h | 9 ++++-- snapshot/fuchsia/process_snapshot_fuchsia.cc | 11 ++++--- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/snapshot/fuchsia/process_reader_fuchsia.cc b/snapshot/fuchsia/process_reader_fuchsia.cc index c8d101b9..c76a1f57 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.cc +++ b/snapshot/fuchsia/process_reader_fuchsia.cc @@ -105,10 +105,6 @@ bool ProcessReaderFuchsia::Initialize(const zx::process& process) { process_memory_.reset(new ProcessMemoryFuchsia()); process_memory_->Initialize(*process_); - if (!memory_map_.Initialize(*process_)) { - return false; - } - INITIALIZATION_STATE_SET_VALID(initialized_); return true; } @@ -135,6 +131,16 @@ ProcessReaderFuchsia::Threads() { return threads_; } +const MemoryMapFuchsia* ProcessReaderFuchsia::MemoryMap() { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + if (!initialized_memory_map_) { + InitializeMemoryMap(); + } + + return memory_map_.get(); +} + void ProcessReaderFuchsia::InitializeModules() { DCHECK(!initialized_modules_); DCHECK(modules_.empty()); @@ -315,7 +321,13 @@ void ProcessReaderFuchsia::InitializeThreads() { } else { thread.general_registers = general_regs; - GetStackRegions(general_regs, memory_map_, &thread.stack_regions); + const MemoryMapFuchsia* memory_map = MemoryMap(); + if (memory_map) { + // Attempt to retrive stack regions if a memory map was retrieved. In + // particular, this may be null when operating on the current process + // where the memory map will not be able to be retrieved. + GetStackRegions(general_regs, *memory_map, &thread.stack_regions); + } } zx_thread_state_vector_regs_t vector_regs; @@ -333,4 +345,15 @@ void ProcessReaderFuchsia::InitializeThreads() { } } +void ProcessReaderFuchsia::InitializeMemoryMap() { + DCHECK(!initialized_memory_map_); + + initialized_memory_map_ = true; + + memory_map_.reset(new MemoryMapFuchsia); + if (!memory_map_->Initialize(*process_)) { + memory_map_.reset(); + } +} + } // namespace crashpad diff --git a/snapshot/fuchsia/process_reader_fuchsia.h b/snapshot/fuchsia/process_reader_fuchsia.h index 1392004e..91c6331c 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.h +++ b/snapshot/fuchsia/process_reader_fuchsia.h @@ -112,7 +112,7 @@ class ProcessReaderFuchsia { const ProcessMemory* Memory() const { return process_memory_.get(); } //! \brief Return a memory map for the target process. - const MemoryMapFuchsia* MemoryMap() const { return &memory_map_; } + const MemoryMapFuchsia* MemoryMap(); private: //! Performs lazy initialization of the \a modules_ vector on behalf of @@ -123,15 +123,20 @@ class ProcessReaderFuchsia { //! Threads(). void InitializeThreads(); + //! Performs lazy initialization of the \a memory_map_ on behalf of + //! MemoryMap(). + void InitializeMemoryMap(); + std::vector<Module> modules_; std::vector<Thread> threads_; std::vector<std::unique_ptr<ElfImageReader>> module_readers_; std::vector<std::unique_ptr<ProcessMemoryRange>> process_memory_ranges_; std::unique_ptr<ProcessMemoryFuchsia> process_memory_; - MemoryMapFuchsia memory_map_; + std::unique_ptr<MemoryMapFuchsia> memory_map_; zx::unowned_process process_; bool initialized_modules_ = false; bool initialized_threads_ = false; + bool initialized_memory_map_ = false; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ProcessReaderFuchsia); diff --git a/snapshot/fuchsia/process_snapshot_fuchsia.cc b/snapshot/fuchsia/process_snapshot_fuchsia.cc index 1ff758d1..294c9f90 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia.cc @@ -41,10 +41,13 @@ bool ProcessSnapshotFuchsia::Initialize(const zx::process& process) { InitializeThreads(); InitializeModules(); - for (const auto& entry : process_reader_.MemoryMap()->Entries()) { - if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) { - memory_map_.push_back( - std::make_unique<internal::MemoryMapRegionSnapshotFuchsia>(entry)); + const MemoryMapFuchsia* memory_map = process_reader_.MemoryMap(); + if (memory_map) { + for (const auto& entry : memory_map->Entries()) { + if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) { + memory_map_.push_back( + std::make_unique<internal::MemoryMapRegionSnapshotFuchsia>(entry)); + } } } From 23a1be41ce3afeefaec27c9f421c2818a309cc4f Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 30 Aug 2019 08:21:23 -0700 Subject: [PATCH 252/401] linux: refactor snapshotting into CaptureSnapshot() Change-Id: I7748f6e4097059d5f57ca7f2f4966534129bda86 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1773773 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- handler/BUILD.gn | 2 + handler/linux/capture_snapshot.cc | 119 ++++++++ handler/linux/capture_snapshot.h | 67 +++++ .../linux/crash_report_exception_handler.cc | 254 +++++++----------- 4 files changed, 284 insertions(+), 158 deletions(-) create mode 100644 handler/linux/capture_snapshot.cc create mode 100644 handler/linux/capture_snapshot.h diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 548073ce..02d6a012 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -42,6 +42,8 @@ static_library("handler") { if (crashpad_is_linux || crashpad_is_android) { set_sources_assignment_filter([]) 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", diff --git a/handler/linux/capture_snapshot.cc b/handler/linux/capture_snapshot.cc new file mode 100644 index 00000000..00540295 --- /dev/null +++ b/handler/linux/capture_snapshot.cc @@ -0,0 +1,119 @@ +// 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. + +#include "handler/linux/capture_snapshot.h" + +#include <utility> + +#include "snapshot/crashpad_info_client_options.h" +#include "snapshot/sanitized/sanitization_information.h" +#include "util/misc/metrics.h" +#include "util/misc/tri_state.h" + +namespace crashpad { + +bool CaptureSnapshot( + PtraceConnection* connection, + const ExceptionHandlerProtocol::ClientInformation& info, + const std::map<std::string, std::string>& process_annotations, + uid_t client_uid, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id, + std::unique_ptr<ProcessSnapshotLinux>* snapshot, + std::unique_ptr<ProcessSnapshotSanitized>* sanitized_snapshot) { + std::unique_ptr<ProcessSnapshotLinux> process_snapshot( + new ProcessSnapshotLinux()); + if (!process_snapshot->Initialize(connection)) { + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed); + return false; + } + + pid_t local_requesting_thread_id = -1; + if (requesting_thread_stack_address) { + local_requesting_thread_id = process_snapshot->FindThreadWithStackAddress( + requesting_thread_stack_address); + } + + if (requesting_thread_id) { + *requesting_thread_id = local_requesting_thread_id; + } + + if (!process_snapshot->InitializeException(info.exception_information_address, + local_requesting_thread_id)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kExceptionInitializationFailed); + return false; + } + + Metrics::ExceptionCode(process_snapshot->Exception()->Exception()); + + CrashpadInfoClientOptions client_options; + process_snapshot->GetCrashpadOptions(&client_options); + if (client_options.crashpad_handler_behavior == TriState::kDisabled) { + return false; + } + + for (auto& p : process_annotations) { + process_snapshot->AddAnnotation(p.first, p.second); + } + + if (info.sanitization_information_address) { + SanitizationInformation sanitization_info; + ProcessMemoryRange range; + if (!range.Initialize(connection->Memory(), connection->Is64Bit()) || + !range.Read(info.sanitization_information_address, + sizeof(sanitization_info), + &sanitization_info)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kSanitizationInitializationFailed); + return false; + } + + auto annotations_whitelist = std::make_unique<std::vector<std::string>>(); + auto memory_range_whitelist = + std::make_unique<std::vector<std::pair<VMAddress, VMAddress>>>(); + if (!ReadAnnotationsWhitelist( + range, + sanitization_info.annotations_whitelist_address, + annotations_whitelist.get()) || + !ReadMemoryRangeWhitelist( + range, + sanitization_info.memory_range_whitelist_address, + memory_range_whitelist.get())) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kSanitizationInitializationFailed); + return false; + } + + std::unique_ptr<ProcessSnapshotSanitized> sanitized( + new ProcessSnapshotSanitized()); + if (!sanitized->Initialize(process_snapshot.get(), + sanitization_info.annotations_whitelist_address + ? std::move(annotations_whitelist) + : nullptr, + std::move(memory_range_whitelist), + sanitization_info.target_module_address, + sanitization_info.sanitize_stacks)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kSkippedDueToSanitization); + return false; + } + *sanitized_snapshot = std::move(sanitized); + } + + *snapshot = std::move(process_snapshot); + return true; +} + +} // namespace crashpad diff --git a/handler/linux/capture_snapshot.h b/handler/linux/capture_snapshot.h new file mode 100644 index 00000000..78886dc5 --- /dev/null +++ b/handler/linux/capture_snapshot.h @@ -0,0 +1,67 @@ +// 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_HANDLER_LINUX_CAPTURE_SNAPSHOT_H_ +#define CRASHPAD_HANDLER_LINUX_CAPTURE_SNAPSHOT_H_ + +#include <sys/types.h> + +#include <map> +#include <memory> +#include <string> + +#include "snapshot/linux/process_snapshot_linux.h" +#include "snapshot/sanitized/process_snapshot_sanitized.h" +#include "util/linux/exception_handler_protocol.h" +#include "util/linux/ptrace_connection.h" +#include "util/misc/address_types.h" + +namespace crashpad { + +//! \brief Captures a snapshot of a client over \a connection. +//! +//! \param[in] connection A PtraceConnection to the client to snapshot. +//! \param[in] info Information about the client configuring the snapshot. +//! \param[in] process_annotations A map of annotations to insert as +//! process-level annotations into the snapshot. +//! \param[in] client_uid The client's user ID. +//! \param[in] requesting_thread_stack_address An address on the stack of the +//! thread requesting the snapshot. If \a info includes an exception +//! address, the exception will be assigned to the thread whose stack +//! address range contains this address. If 0, \a requesting_thread_id will +//! be -1. +//! \param[out] requesting_thread_id The thread ID of the thread corresponding +//! to \a requesting_thread_stack_address. Set to -1 if the thread ID could +//! not be determined. Optional. +//! \param[out] process_snapshot A snapshot of the client process, valid if this +//! function returns `true`. +//! \param[out] sanitized_snapshot A sanitized snapshot of the client process, +//! valid if this function returns `true` and sanitization was requested in +//! \a info. +//! \return `true` if \a process_snapshot was successfully created. A message +//! will be logged on failure, but not if the snapshot was skipped because +//! handling was disabled by CrashpadInfoClientOptions. +bool CaptureSnapshot( + PtraceConnection* connection, + const ExceptionHandlerProtocol::ClientInformation& info, + const std::map<std::string, std::string>& process_annotations, + uid_t client_uid, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id, + std::unique_ptr<ProcessSnapshotLinux>* process_snapshot, + std::unique_ptr<ProcessSnapshotSanitized>* sanitized_snapshot); + +} // namespace crashpad + +#endif // CRASHPAD_HANDLER_LINUX_CAPTURE_SNAPSHOT_H_ diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 48ff724c..073e72bd 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -14,19 +14,19 @@ #include "handler/linux/crash_report_exception_handler.h" +#include <memory> +#include <utility> #include <vector> #include "base/logging.h" #include "client/settings.h" +#include "handler/linux/capture_snapshot.h" #include "minidump/minidump_file_writer.h" -#include "snapshot/crashpad_info_client_options.h" #include "snapshot/linux/process_snapshot_linux.h" #include "snapshot/sanitized/process_snapshot_sanitized.h" -#include "snapshot/sanitized/sanitization_information.h" #include "util/linux/direct_ptrace_connection.h" #include "util/linux/ptrace_client.h" #include "util/misc/metrics.h" -#include "util/misc/tri_state.h" #include "util/misc/uuid.h" #if defined(OS_CHROMEOS) @@ -195,188 +195,126 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( VMAddress requesting_thread_stack_address, pid_t* requesting_thread_id, UUID* local_report_id) { - ProcessSnapshotLinux process_snapshot; - if (!process_snapshot.Initialize(connection)) { - Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed); + std::unique_ptr<ProcessSnapshotLinux> process_snapshot; + std::unique_ptr<ProcessSnapshotSanitized> sanitized_snapshot; + if (!CaptureSnapshot(connection, + info, + *process_annotations_, + client_uid, + requesting_thread_stack_address, + requesting_thread_id, + &process_snapshot, + &sanitized_snapshot)) { return false; } - pid_t local_requesting_thread_id = -1; - if (requesting_thread_stack_address) { - local_requesting_thread_id = process_snapshot.FindThreadWithStackAddress( - requesting_thread_stack_address); + UUID client_id; + Settings* const settings = database_->GetSettings(); + if (settings) { + // If GetSettings() or GetClientID() fails, something else will log a + // message and client_id will be left at its default value, all zeroes, + // which is appropriate. + settings->GetClientID(&client_id); } + process_snapshot->SetClientID(client_id); - if (requesting_thread_id) { - *requesting_thread_id = local_requesting_thread_id; - } + UUID uuid; +#if defined(OS_CHROMEOS) + uuid.InitializeWithNew(); + process_snapshot->SetReportID(uuid); +#else - if (!process_snapshot.InitializeException(info.exception_information_address, - local_requesting_thread_id)) { + std::unique_ptr<CrashReportDatabase::NewReport> new_report; + CrashReportDatabase::OperationStatus database_status = + database_->PrepareNewCrashReport(&new_report); + if (database_status != CrashReportDatabase::kNoError) { + LOG(ERROR) << "PrepareNewCrashReport failed"; Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kExceptionInitializationFailed); + Metrics::CaptureResult::kPrepareNewCrashReportFailed); return false; } - Metrics::ExceptionCode(process_snapshot.Exception()->Exception()); - - CrashpadInfoClientOptions client_options; - process_snapshot.GetCrashpadOptions(&client_options); - if (client_options.crashpad_handler_behavior != TriState::kDisabled) { - UUID client_id; - Settings* const settings = database_->GetSettings(); - if (settings) { - // If GetSettings() or GetClientID() fails, something else will log a - // message and client_id will be left at its default value, all zeroes, - // which is appropriate. - settings->GetClientID(&client_id); - } - - process_snapshot.SetClientID(client_id); - for (auto& p : *process_annotations_) { - process_snapshot.AddAnnotation(p.first, p.second); - } - - UUID uuid; -#if defined(OS_CHROMEOS) - uuid.InitializeWithNew(); - process_snapshot.SetReportID(uuid); -#else - - std::unique_ptr<CrashReportDatabase::NewReport> new_report; - CrashReportDatabase::OperationStatus database_status = - database_->PrepareNewCrashReport(&new_report); - if (database_status != CrashReportDatabase::kNoError) { - LOG(ERROR) << "PrepareNewCrashReport failed"; - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kPrepareNewCrashReportFailed); - return false; - } - - process_snapshot.SetReportID(new_report->ReportID()); + process_snapshot->SetReportID(new_report->ReportID()); #endif - ProcessSnapshot* snapshot = nullptr; - ProcessSnapshotSanitized sanitized; - if (info.sanitization_information_address) { - SanitizationInformation sanitization_info; - ProcessMemoryRange range; - if (!range.Initialize(connection->Memory(), connection->Is64Bit()) || - !range.Read(info.sanitization_information_address, - sizeof(sanitization_info), - &sanitization_info)) { - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kSanitizationInitializationFailed); - return false; - } + ProcessSnapshot* snapshot = + sanitized_snapshot + ? implicit_cast<ProcessSnapshot*>(sanitized_snapshot.get()) + : implicit_cast<ProcessSnapshot*>(process_snapshot.get()); - auto annotations_whitelist = std::make_unique<std::vector<std::string>>(); - auto memory_range_whitelist = - std::make_unique<std::vector<std::pair<VMAddress, VMAddress>>>(); - if (!ReadAnnotationsWhitelist( - range, - sanitization_info.annotations_whitelist_address, - annotations_whitelist.get()) || - !ReadMemoryRangeWhitelist( - range, - sanitization_info.memory_range_whitelist_address, - memory_range_whitelist.get())) { - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kSanitizationInitializationFailed); - return false; - } - - if (!sanitized.Initialize(&process_snapshot, - sanitization_info.annotations_whitelist_address - ? std::move(annotations_whitelist) - : nullptr, - std::move(memory_range_whitelist), - sanitization_info.target_module_address, - sanitization_info.sanitize_stacks)) { - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kSkippedDueToSanitization); - return true; - } - - snapshot = &sanitized; - } else { - snapshot = &process_snapshot; - } - - MinidumpFileWriter minidump; - minidump.InitializeFromSnapshot(snapshot); - AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump); + MinidumpFileWriter minidump; + minidump.InitializeFromSnapshot(snapshot); + AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump); #if defined(OS_CHROMEOS) - FileWriter file_writer; - if (!file_writer.OpenMemfd(base::FilePath("/tmp/minidump"))) { - Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kOpenMemfdFailed); - return false; - } + FileWriter file_writer; + if (!file_writer.OpenMemfd(base::FilePath("/tmp/minidump"))) { + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kOpenMemfdFailed); + return false; + } - std::map<std::string, std::string> parameters = - BreakpadHTTPFormParametersFromMinidump(snapshot); - // Used to differenciate between breakpad and crashpad while the switch is - // ramping up. - parameters.emplace("crash_library", "crashpad"); + std::map<std::string, std::string> parameters = + BreakpadHTTPFormParametersFromMinidump(snapshot); + // Used to differenciate between breakpad and crashpad while the switch is + // ramping up. + parameters.emplace("crash_library", "crashpad"); - if (!WriteAnnotationsAndMinidump(parameters, minidump, file_writer)) { - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kMinidumpWriteFailed); - return false; - } + if (!WriteAnnotationsAndMinidump(parameters, minidump, file_writer)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kMinidumpWriteFailed); + return false; + } - // CrOS uses crash_reporter instead of Crashpad to report crashes. - // crash_reporter needs to know the pid and uid of the crashing process. - std::vector<std::string> argv({"/sbin/crash_reporter"}); + // CrOS uses crash_reporter instead of Crashpad to report crashes. + // crash_reporter needs to know the pid and uid of the crashing process. + std::vector<std::string> argv({"/sbin/crash_reporter"}); - argv.push_back("--chrome_memfd=" + std::to_string(file_writer.fd())); - argv.push_back("--pid=" + std::to_string(*requesting_thread_id)); - argv.push_back("--uid=" + std::to_string(client_uid)); - std::string process_name = GetProcessNameFromPid(*requesting_thread_id); - argv.push_back("--exe=" + (process_name.empty() ? "chrome" : process_name)); + argv.push_back("--chrome_memfd=" + std::to_string(file_writer.fd())); + argv.push_back("--pid=" + std::to_string(*requesting_thread_id)); + argv.push_back("--uid=" + std::to_string(client_uid)); + std::string process_name = GetProcessNameFromPid(*requesting_thread_id); + argv.push_back("--exe=" + (process_name.empty() ? "chrome" : process_name)); - if (info.crash_loop_before_time != 0) { - argv.push_back("--crash_loop_before=" + - std::to_string(info.crash_loop_before_time)); - } + if (info.crash_loop_before_time != 0) { + argv.push_back("--crash_loop_before=" + + std::to_string(info.crash_loop_before_time)); + } - if (!DoubleForkAndExec(argv, - nullptr /* envp */, - file_writer.fd() /* preserve_fd */, - false /* use_path */, - nullptr /* child_function */)) { - LOG(ERROR) << "DoubleForkAndExec failed"; - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kFinishedWritingCrashReportFailed); - return false; - } + if (!DoubleForkAndExec(argv, + nullptr /* envp */, + file_writer.fd() /* preserve_fd */, + false /* use_path */, + nullptr /* child_function */)) { + LOG(ERROR) << "DoubleForkAndExec failed"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kFinishedWritingCrashReportFailed); + return false; + } #else - if (!minidump.WriteEverything(new_report->Writer())) { - LOG(ERROR) << "WriteEverything failed"; - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kMinidumpWriteFailed); - return false; - } + if (!minidump.WriteEverything(new_report->Writer())) { + LOG(ERROR) << "WriteEverything failed"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kMinidumpWriteFailed); + return false; + } - database_status = - database_->FinishedWritingCrashReport(std::move(new_report), &uuid); - if (database_status != CrashReportDatabase::kNoError) { - LOG(ERROR) << "FinishedWritingCrashReport failed"; - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kFinishedWritingCrashReportFailed); - return false; - } + database_status = + database_->FinishedWritingCrashReport(std::move(new_report), &uuid); + if (database_status != CrashReportDatabase::kNoError) { + LOG(ERROR) << "FinishedWritingCrashReport failed"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kFinishedWritingCrashReportFailed); + return false; + } - if (upload_thread_) { - upload_thread_->ReportPending(uuid); - } + if (upload_thread_) { + upload_thread_->ReportPending(uuid); + } #endif - if (local_report_id != nullptr) { - *local_report_id = uuid; - } + if (local_report_id != nullptr) { + *local_report_id = uuid; } Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess); From 80473094a4d216f6d5a483a4748dacc8eef0f098 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 30 Aug 2019 11:45:54 -0700 Subject: [PATCH 253/401] linux, compat: add a memfd_create wrapper Change-Id: Iecbf85d0e963779b4c16083b481f4ab50f509115 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1774899 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- compat/BUILD.gn | 2 ++ compat/linux/sys/mman.cc | 35 +++++++++++++++++++++++++++++++++++ compat/linux/sys/mman.h | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 compat/linux/sys/mman.cc create mode 100644 compat/linux/sys/mman.h diff --git a/compat/BUILD.gn b/compat/BUILD.gn index 7a33d7ca..62ee5286 100644 --- a/compat/BUILD.gn +++ b/compat/BUILD.gn @@ -79,6 +79,8 @@ compat_target("compat") { if (crashpad_is_linux || crashpad_is_android) { sources += [ "linux/signal.h", + "linux/sys/mman.cc", + "linux/sys/mman.h", "linux/sys/ptrace.h", "linux/sys/user.h", ] diff --git a/compat/linux/sys/mman.cc b/compat/linux/sys/mman.cc new file mode 100644 index 00000000..12aaa2c7 --- /dev/null +++ b/compat/linux/sys/mman.cc @@ -0,0 +1,35 @@ +// 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. + +#include <sys/mman.h> + +#include <dlfcn.h> +#include <sys/syscall.h> +#include <unistd.h> + +#if defined(__GLIBC__) + +extern "C" { + +int memfd_create(const char* name, unsigned int flags) { + using MemfdCreateType = int (*)(const char*, int); + static const MemfdCreateType next_memfd_create = + reinterpret_cast<MemfdCreateType>(dlsym(RTLD_NEXT, "memfd_create")); + return next_memfd_create ? next_memfd_create(name, flags) + : syscall(SYS_memfd_create, name, flags); +} + +} // extern "C" + +#endif // __GLIBC__ diff --git a/compat/linux/sys/mman.h b/compat/linux/sys/mman.h new file mode 100644 index 00000000..61c55d7b --- /dev/null +++ b/compat/linux/sys/mman.h @@ -0,0 +1,40 @@ +// 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_LINUX_SYS_MMAN_H_ +#define CRASHPAD_COMPAT_LINUX_SYS_MMAN_H_ + +#include_next <sys/mman.h> + +#include <features.h> + +// There's no memfd_create() wrapper before glibc 2.27. +// This can't select for glibc < 2.27 because linux-chromeos-rel bots build this +// code using a sysroot which has glibc 2.27, but then run it on Ubuntu 16.04, +// which doesn't. +#if defined(__GLIBC__) + +#ifdef __cplusplus +extern "C" { +#endif + +int memfd_create(const char* name, unsigned int flags); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __GLIBC__ + +#endif // CRASHPAD_COMPAT_LINUX_SYS_MMAN_H_ From cd92fba233d3cc28909c3791710a747c818de244 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 30 Aug 2019 11:51:47 -0700 Subject: [PATCH 254/401] linux: Move Cros crash handling to CrosCrashReportExceptionHandler Change-Id: I80686ddc35b03fa213481e35dc494a40fbdd551a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1775222 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- handler/BUILD.gn | 7 + handler/handler_main.cc | 56 +++- .../linux/crash_report_exception_handler.cc | 163 +--------- .../linux/crash_report_exception_handler.h | 4 +- .../cros_crash_report_exception_handler.cc | 278 ++++++++++++++++++ .../cros_crash_report_exception_handler.h | 97 ++++++ handler/linux/exception_handler_server.h | 3 +- handler/mac/crash_report_exception_handler.h | 3 +- handler/win/crash_report_exception_handler.h | 3 +- util/file/file_io.h | 4 +- util/file/file_io_posix.cc | 4 +- util/file/file_writer.cc | 2 +- util/file/file_writer.h | 2 +- util/linux/exception_handler_protocol.h | 5 +- 14 files changed, 453 insertions(+), 178 deletions(-) create mode 100644 handler/linux/cros_crash_report_exception_handler.cc create mode 100644 handler/linux/cros_crash_report_exception_handler.h diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 02d6a012..6df147a8 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -51,6 +51,13 @@ static_library("handler") { ] } + if (crashpad_is_linux) { + sources += [ + "linux/cros_crash_report_exception_handler.cc", + "linux/cros_crash_report_exception_handler.h", + ] + } + if (crashpad_is_win) { sources += [ "win/crash_report_exception_handler.cc", diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 91e3436f..7b69e848 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -56,6 +56,10 @@ #include "util/string/split_string.h" #include "util/synchronization/semaphore.h" +#if defined(OS_CHROMEOS) +#include "handler/linux/cros_crash_report_exception_handler.h" +#endif + #if defined(OS_LINUX) || defined(OS_ANDROID) #include <unistd.h> @@ -157,6 +161,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_CHROMEOS) +" --use-cros-crash-reporter\n" +#endif // OS_CHROMEOS " --help display this help and exit\n" " --version output version information and exit\n", me.value().c_str()); @@ -188,6 +195,9 @@ struct Options { bool periodic_tasks; bool rate_limit; bool upload_gzip; +#if defined(OS_CHROMEOS) + bool use_cros_crash_reporter; +#endif // OS_CHROMEOS }; // Splits |key_value| on '=' and inserts the resulting key and value into |map|. @@ -559,6 +569,9 @@ int HandlerMain(int argc, kOptionTraceParentWithException, #endif kOptionURL, +#if defined(OS_CHROMEOS) + kOptionUseCrosCrashReporter, +#endif // OS_CHROMEOS // Standard options. kOptionHelp = -2, @@ -624,6 +637,12 @@ int HandlerMain(int argc, kOptionTraceParentWithException}, #endif // OS_LINUX || OS_ANDROID {"url", required_argument, nullptr, kOptionURL}, +#if defined(OS_CHROEMOS) + {"use-cros-crash-reporter", + no_argument, + nullptr, + kOptionUseCrosCrashReporter}, +#endif // OS_CHROMEOS {"help", no_argument, nullptr, kOptionHelp}, {"version", no_argument, nullptr, kOptionVersion}, {nullptr, 0, nullptr, 0}, @@ -765,6 +784,12 @@ int HandlerMain(int argc, options.url = optarg; break; } +#if defined(OS_CHROMEOS) + case kOptionUseCrosCrashReporter: { + options.use_cros_crash_reporter = true; + break; + } +#endif // OS_CHROMEOS case kOptionHelp: { Usage(me); MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); @@ -890,7 +915,27 @@ int HandlerMain(int argc, upload_thread.Get()->Start(); } - CrashReportExceptionHandler exception_handler( +#if defined(OS_LINUX) || defined(OS_ANDROID) + std::unique_ptr<ExceptionHandlerServer::Delegate> exception_handler; +#else + std::unique_ptr<CrashReportExceptionHandler> exception_handler; +#endif + +#if defined(OS_CHROMEOS) + if (options.use_cros_crash_reporter) { + exception_handler = std::make_unique<CrosCrashReportExceptionHandler>( + database.get(), + &options.annotations, + user_stream_sources); + } else { + exception_handler = std::make_unique<CrashReportExceptionHandler>( + database.get(), + static_cast<CrashReportUploadThread*>(upload_thread.Get()), + &options.annotations, + user_stream_sources); + } +#else + exception_handler = std::make_unique<CrashReportExceptionHandler>( database.get(), static_cast<CrashReportUploadThread*>(upload_thread.Get()), &options.annotations, @@ -899,14 +944,15 @@ int HandlerMain(int argc, nullptr, #endif user_stream_sources); +#endif // OS_CHROMEOS - #if defined(OS_LINUX) || defined(OS_ANDROID) +#if defined(OS_LINUX) || defined(OS_ANDROID) if (options.exception_information_address) { ExceptionHandlerProtocol::ClientInformation info; info.exception_information_address = options.exception_information_address; info.sanitization_information_address = options.sanitization_information_address; - return exception_handler.HandleException(getppid(), geteuid(), info) + return exception_handler->HandleException(getppid(), geteuid(), info) ? EXIT_SUCCESS : ExitFailure(); } @@ -1012,7 +1058,7 @@ int HandlerMain(int argc, #if defined(OS_WIN) if (options.initial_client_data.IsValid()) { exception_handler_server.InitializeWithInheritedDataForInitialClient( - options.initial_client_data, &exception_handler); + options.initial_client_data, exception_handler.get()); } #elif defined(OS_LINUX) || defined(OS_ANDROID) if (options.initial_client_fd == kInvalidFileHandle || @@ -1023,7 +1069,7 @@ int HandlerMain(int argc, } #endif // OS_WIN - exception_handler_server.Run(&exception_handler); + exception_handler_server.Run(exception_handler.get()); return EXIT_SUCCESS; } diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 073e72bd..9b4f2012 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -16,7 +16,6 @@ #include <memory> #include <utility> -#include <vector> #include "base/logging.h" #include "client/settings.h" @@ -26,108 +25,10 @@ #include "snapshot/sanitized/process_snapshot_sanitized.h" #include "util/linux/direct_ptrace_connection.h" #include "util/linux/ptrace_client.h" +#include "util/misc/implicit_cast.h" #include "util/misc/metrics.h" #include "util/misc/uuid.h" -#if defined(OS_CHROMEOS) -#include "handler/minidump_to_upload_parameters.h" -#include "snapshot/minidump/process_snapshot_minidump.h" -#include "util/posix/double_fork_and_exec.h" - -namespace { -// Returns the process name for a pid. -const std::string GetProcessNameFromPid(pid_t pid) { - // Symlink to process binary is at /proc/###/exe. - std::string link_path = "/proc/" + std::to_string(pid) + "/exe"; - - constexpr int kMaxSize = 4096; - std::unique_ptr<char[]> buf(new char[kMaxSize]); - ssize_t size = readlink(link_path.c_str(), buf.get(), kMaxSize); - std::string result; - if (size < 0) { - PLOG(ERROR) << "Failed to readlink " << link_path; - } else { - result.assign(buf.get(), size); - size_t last_slash_pos = result.rfind('/'); - if (last_slash_pos != std::string::npos) { - result = result.substr(last_slash_pos + 1); - } - } - return result; -} - -bool WriteAnnotationsAndMinidump( - const std::map<std::string, std::string>& parameters, - crashpad::MinidumpFileWriter& minidump, - crashpad::FileWriter& file_writer) { - for (const auto& kv : parameters) { - if (kv.first.find(':') != std::string::npos) { - LOG(ERROR) << "Annotation key cannot have ':' in it " << kv.first; - return false; - } - if (!file_writer.Write(kv.first.c_str(), strlen(kv.first.c_str()))) { - return false; - } - if (!file_writer.Write(":", 1)) { - return false; - } - size_t value_size = strlen(kv.second.c_str()); - std::string value_size_str = std::to_string(value_size); - if (!file_writer.Write(value_size_str.c_str(), value_size_str.size())) { - return false; - } - if (!file_writer.Write(":", 1)) { - return false; - } - if (!file_writer.Write(kv.second.c_str(), strlen(kv.second.c_str()))) { - return false; - } - } - - static constexpr char kMinidumpName[] = - "upload_file_minidump\"; filename=\"dump\":"; - if (!file_writer.Write(kMinidumpName, sizeof(kMinidumpName) - 1)) { - return false; - } - crashpad::FileOffset dump_size_start_offset = file_writer.Seek(0, SEEK_CUR); - if (dump_size_start_offset < 0) { - LOG(ERROR) << "Failed to get minidump size start offset"; - return false; - } - static constexpr char kMinidumpLengthFilling[] = "00000000000000000000:"; - if (!file_writer.Write(kMinidumpLengthFilling, - sizeof(kMinidumpLengthFilling) - 1)) { - return false; - } - crashpad::FileOffset dump_start_offset = file_writer.Seek(0, SEEK_CUR); - if (dump_start_offset < 0) { - LOG(ERROR) << "Failed to get minidump start offset"; - return false; - } - if (!minidump.WriteEverything(&file_writer)) { - return false; - } - crashpad::FileOffset dump_end_offset = file_writer.Seek(0, SEEK_CUR); - if (dump_end_offset < 0) { - LOG(ERROR) << "Failed to get minidump end offset"; - return false; - } - - size_t dump_data_size = dump_end_offset - dump_start_offset; - std::string dump_data_size_str = std::to_string(dump_data_size); - file_writer.Seek(dump_size_start_offset + strlen(kMinidumpLengthFilling) - 1 - - dump_data_size_str.size(), - SEEK_SET); - if (!file_writer.Write(dump_data_size_str.c_str(), - dump_data_size_str.size())) { - return false; - } - return true; -} - -} // namespace -#endif // defined(OS_CHROMEOS) - namespace crashpad { CrashReportExceptionHandler::CrashReportExceptionHandler( @@ -136,12 +37,9 @@ CrashReportExceptionHandler::CrashReportExceptionHandler( const std::map<std::string, std::string>* process_annotations, const UserStreamDataSources* user_stream_data_sources) : database_(database), -#if !defined(OS_CHROMEOS) upload_thread_(upload_thread), -#endif process_annotations_(process_annotations), - user_stream_data_sources_(user_stream_data_sources) { -} + user_stream_data_sources_(user_stream_data_sources) {} CrashReportExceptionHandler::~CrashReportExceptionHandler() = default; @@ -218,12 +116,6 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( } process_snapshot->SetClientID(client_id); - UUID uuid; -#if defined(OS_CHROMEOS) - uuid.InitializeWithNew(); - process_snapshot->SetReportID(uuid); -#else - std::unique_ptr<CrashReportDatabase::NewReport> new_report; CrashReportDatabase::OperationStatus database_status = database_->PrepareNewCrashReport(&new_report); @@ -235,7 +127,6 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( } process_snapshot->SetReportID(new_report->ReportID()); -#endif ProcessSnapshot* snapshot = sanitized_snapshot @@ -246,53 +137,6 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( minidump.InitializeFromSnapshot(snapshot); AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump); -#if defined(OS_CHROMEOS) - FileWriter file_writer; - if (!file_writer.OpenMemfd(base::FilePath("/tmp/minidump"))) { - Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kOpenMemfdFailed); - return false; - } - - std::map<std::string, std::string> parameters = - BreakpadHTTPFormParametersFromMinidump(snapshot); - // Used to differenciate between breakpad and crashpad while the switch is - // ramping up. - parameters.emplace("crash_library", "crashpad"); - - if (!WriteAnnotationsAndMinidump(parameters, minidump, file_writer)) { - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kMinidumpWriteFailed); - return false; - } - - // CrOS uses crash_reporter instead of Crashpad to report crashes. - // crash_reporter needs to know the pid and uid of the crashing process. - std::vector<std::string> argv({"/sbin/crash_reporter"}); - - argv.push_back("--chrome_memfd=" + std::to_string(file_writer.fd())); - argv.push_back("--pid=" + std::to_string(*requesting_thread_id)); - argv.push_back("--uid=" + std::to_string(client_uid)); - std::string process_name = GetProcessNameFromPid(*requesting_thread_id); - argv.push_back("--exe=" + (process_name.empty() ? "chrome" : process_name)); - - if (info.crash_loop_before_time != 0) { - argv.push_back("--crash_loop_before=" + - std::to_string(info.crash_loop_before_time)); - } - - if (!DoubleForkAndExec(argv, - nullptr /* envp */, - file_writer.fd() /* preserve_fd */, - false /* use_path */, - nullptr /* child_function */)) { - LOG(ERROR) << "DoubleForkAndExec failed"; - Metrics::ExceptionCaptureResult( - Metrics::CaptureResult::kFinishedWritingCrashReportFailed); - return false; - } - -#else - if (!minidump.WriteEverything(new_report->Writer())) { LOG(ERROR) << "WriteEverything failed"; Metrics::ExceptionCaptureResult( @@ -300,6 +144,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( return false; } + UUID uuid; database_status = database_->FinishedWritingCrashReport(std::move(new_report), &uuid); if (database_status != CrashReportDatabase::kNoError) { @@ -312,7 +157,7 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( if (upload_thread_) { upload_thread_->ReportPending(uuid); } -#endif + if (local_report_id != nullptr) { *local_report_id = uuid; } diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index ca527587..522a77de 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -60,7 +60,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { const std::map<std::string, std::string>* process_annotations, const UserStreamDataSources* user_stream_data_sources); - ~CrashReportExceptionHandler(); + ~CrashReportExceptionHandler() override; // ExceptionHandlerServer::Delegate: @@ -88,9 +88,7 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { UUID* local_report_id = nullptr); CrashReportDatabase* database_; // weak -#if !defined(OS_CHROMEOS) CrashReportUploadThread* upload_thread_; // weak -#endif const std::map<std::string, std::string>* process_annotations_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak diff --git a/handler/linux/cros_crash_report_exception_handler.cc b/handler/linux/cros_crash_report_exception_handler.cc new file mode 100644 index 00000000..a24b17f6 --- /dev/null +++ b/handler/linux/cros_crash_report_exception_handler.cc @@ -0,0 +1,278 @@ +// 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. + +#include "handler/linux/cros_crash_report_exception_handler.h" + +#include <vector> + +#include "base/logging.h" +#include "client/settings.h" +#include "handler/linux/capture_snapshot.h" +#include "handler/minidump_to_upload_parameters.h" +#include "minidump/minidump_file_writer.h" +#include "snapshot/linux/process_snapshot_linux.h" +#include "snapshot/minidump/process_snapshot_minidump.h" +#include "snapshot/sanitized/process_snapshot_sanitized.h" +#include "util/file/file_writer.h" +#include "util/linux/direct_ptrace_connection.h" +#include "util/linux/ptrace_client.h" +#include "util/misc/metrics.h" +#include "util/misc/uuid.h" +#include "util/posix/double_fork_and_exec.h" + +namespace crashpad { + +namespace { + +// Returns the process name for a pid. +const std::string GetProcessNameFromPid(pid_t pid) { + // Symlink to process binary is at /proc/###/exe. + std::string link_path = "/proc/" + std::to_string(pid) + "/exe"; + + constexpr int kMaxSize = 4096; + std::unique_ptr<char[]> buf(new char[kMaxSize]); + ssize_t size = readlink(link_path.c_str(), buf.get(), kMaxSize); + std::string result; + if (size < 0) { + PLOG(ERROR) << "Failed to readlink " << link_path; + } else { + result.assign(buf.get(), size); + size_t last_slash_pos = result.rfind('/'); + if (last_slash_pos != std::string::npos) { + result = result.substr(last_slash_pos + 1); + } + } + return result; +} + +bool WriteAnnotationsAndMinidump( + const std::map<std::string, std::string>& parameters, + MinidumpFileWriter& minidump, + FileWriter& file_writer) { + for (const auto& kv : parameters) { + if (kv.first.find(':') != std::string::npos) { + LOG(ERROR) << "Annotation key cannot have ':' in it " << kv.first; + return false; + } + if (!file_writer.Write(kv.first.c_str(), strlen(kv.first.c_str()))) { + return false; + } + if (!file_writer.Write(":", 1)) { + return false; + } + size_t value_size = strlen(kv.second.c_str()); + std::string value_size_str = std::to_string(value_size); + if (!file_writer.Write(value_size_str.c_str(), value_size_str.size())) { + return false; + } + if (!file_writer.Write(":", 1)) { + return false; + } + if (!file_writer.Write(kv.second.c_str(), strlen(kv.second.c_str()))) { + return false; + } + } + + static constexpr char kMinidumpName[] = + "upload_file_minidump\"; filename=\"dump\":"; + if (!file_writer.Write(kMinidumpName, sizeof(kMinidumpName) - 1)) { + return false; + } + crashpad::FileOffset dump_size_start_offset = file_writer.Seek(0, SEEK_CUR); + if (dump_size_start_offset < 0) { + LOG(ERROR) << "Failed to get minidump size start offset"; + return false; + } + static constexpr char kMinidumpLengthFilling[] = "00000000000000000000:"; + if (!file_writer.Write(kMinidumpLengthFilling, + sizeof(kMinidumpLengthFilling) - 1)) { + return false; + } + crashpad::FileOffset dump_start_offset = file_writer.Seek(0, SEEK_CUR); + if (dump_start_offset < 0) { + LOG(ERROR) << "Failed to get minidump start offset"; + return false; + } + if (!minidump.WriteEverything(&file_writer)) { + return false; + } + crashpad::FileOffset dump_end_offset = file_writer.Seek(0, SEEK_CUR); + if (dump_end_offset < 0) { + LOG(ERROR) << "Failed to get minidump end offset"; + return false; + } + + size_t dump_data_size = dump_end_offset - dump_start_offset; + std::string dump_data_size_str = std::to_string(dump_data_size); + file_writer.Seek(dump_size_start_offset + strlen(kMinidumpLengthFilling) - 1 - + dump_data_size_str.size(), + SEEK_SET); + if (!file_writer.Write(dump_data_size_str.c_str(), + dump_data_size_str.size())) { + return false; + } + return true; +} + +} // namespace + +CrosCrashReportExceptionHandler::CrosCrashReportExceptionHandler( + CrashReportDatabase* database, + const std::map<std::string, std::string>* process_annotations, + const UserStreamDataSources* user_stream_data_sources) + : database_(database), + process_annotations_(process_annotations), + user_stream_data_sources_(user_stream_data_sources) {} + +CrosCrashReportExceptionHandler::~CrosCrashReportExceptionHandler() = default; + +bool CrosCrashReportExceptionHandler::HandleException( + pid_t client_process_id, + uid_t client_uid, + const ExceptionHandlerProtocol::ClientInformation& info, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id, + UUID* local_report_id) { + Metrics::ExceptionEncountered(); + + DirectPtraceConnection connection; + if (!connection.Initialize(client_process_id)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kDirectPtraceFailed); + return false; + } + + return HandleExceptionWithConnection(&connection, + info, + client_uid, + requesting_thread_stack_address, + requesting_thread_id, + local_report_id); +} + +bool CrosCrashReportExceptionHandler::HandleExceptionWithBroker( + pid_t client_process_id, + uid_t client_uid, + const ExceptionHandlerProtocol::ClientInformation& info, + int broker_sock, + UUID* local_report_id) { + Metrics::ExceptionEncountered(); + + PtraceClient client; + if (!client.Initialize(broker_sock, client_process_id)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kBrokeredPtraceFailed); + return false; + } + + return HandleExceptionWithConnection( + &client, info, client_uid, 0, nullptr, local_report_id); +} + +bool CrosCrashReportExceptionHandler::HandleExceptionWithConnection( + PtraceConnection* connection, + const ExceptionHandlerProtocol::ClientInformation& info, + uid_t client_uid, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id, + UUID* local_report_id) { + std::unique_ptr<ProcessSnapshotLinux> process_snapshot; + std::unique_ptr<ProcessSnapshotSanitized> sanitized_snapshot; + if (!CaptureSnapshot(connection, + info, + *process_annotations_, + client_uid, + requesting_thread_stack_address, + requesting_thread_id, + &process_snapshot, + &sanitized_snapshot)) { + return false; + } + + UUID client_id; + Settings* const settings = database_->GetSettings(); + if (settings) { + // If GetSettings() or GetClientID() fails, something else will log a + // message and client_id will be left at its default value, all zeroes, + // which is appropriate. + settings->GetClientID(&client_id); + } + process_snapshot->SetClientID(client_id); + + UUID uuid; + uuid.InitializeWithNew(); + process_snapshot->SetReportID(uuid); + + ProcessSnapshot* snapshot = + sanitized_snapshot + ? implicit_cast<ProcessSnapshot*>(sanitized_snapshot.get()) + : implicit_cast<ProcessSnapshot*>(process_snapshot.get()); + + MinidumpFileWriter minidump; + minidump.InitializeFromSnapshot(snapshot); + AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump); + + FileWriter file_writer; + if (!file_writer.OpenMemfd(base::FilePath("/tmp/minidump"))) { + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kOpenMemfdFailed); + return false; + } + + std::map<std::string, std::string> parameters = + BreakpadHTTPFormParametersFromMinidump(snapshot); + // Used to differentiate between breakpad and crashpad while the switch is + // ramping up. + parameters.emplace("crash_library", "crashpad"); + + if (!WriteAnnotationsAndMinidump(parameters, minidump, file_writer)) { + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kMinidumpWriteFailed); + return false; + } + + // CrOS uses crash_reporter instead of Crashpad to report crashes. + // crash_reporter needs to know the pid and uid of the crashing process. + std::vector<std::string> argv({"/sbin/crash_reporter"}); + + argv.push_back("--chrome_memfd=" + std::to_string(file_writer.fd())); + argv.push_back("--pid=" + std::to_string(*requesting_thread_id)); + argv.push_back("--uid=" + std::to_string(client_uid)); + std::string process_name = GetProcessNameFromPid(*requesting_thread_id); + argv.push_back("--exe=" + (process_name.empty() ? "chrome" : process_name)); + + if (info.crash_loop_before_time != 0) { + argv.push_back("--crash_loop_before=" + + std::to_string(info.crash_loop_before_time)); + } + + if (!DoubleForkAndExec(argv, + nullptr /* envp */, + file_writer.fd() /* preserve_fd */, + false /* use_path */, + nullptr /* child_function */)) { + LOG(ERROR) << "DoubleForkAndExec failed"; + Metrics::ExceptionCaptureResult( + Metrics::CaptureResult::kFinishedWritingCrashReportFailed); + return false; + } + + if (local_report_id != nullptr) { + *local_report_id = uuid; + } + + Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess); + return true; +} + +} // namespace crashpad diff --git a/handler/linux/cros_crash_report_exception_handler.h b/handler/linux/cros_crash_report_exception_handler.h new file mode 100644 index 00000000..f6ca445b --- /dev/null +++ b/handler/linux/cros_crash_report_exception_handler.h @@ -0,0 +1,97 @@ +// 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_HANDLER_LINUX_CROS_CRASH_REPORT_EXCEPTION_HANDLER_H_ +#define CRASHPAD_HANDLER_LINUX_CROS_CRASH_REPORT_EXCEPTION_HANDLER_H_ + +#include <map> +#include <string> + +#include "base/macros.h" +#include "client/crash_report_database.h" +#include "handler/linux/exception_handler_server.h" +#include "handler/user_stream_data_source.h" +#include "util/linux/exception_handler_protocol.h" +#include "util/linux/ptrace_connection.h" +#include "util/misc/address_types.h" +#include "util/misc/uuid.h" + +namespace crashpad { + +//! \brief An exception handler that writes crash reports to the ChromeOS +//! crash_reporter. +class CrosCrashReportExceptionHandler + : public ExceptionHandlerServer::Delegate { + public: + //! \brief Creates a new object that will pass reports to + //! `/sbin/crash_reporter`. + //! + //! \param[in] database The database that supplies settings for this client. + //! This object does not write its reports to this database. + //! \param[in] process_annotations A map of annotations to insert as + //! process-level annotations into each crash report that is written. Do + //! not confuse this with module-level annotations, which are under the + //! control of the crashing process, and are used to implement Chrome’s + //! “crash keys.” Process-level annotations are those that are beyond the + //! control of the crashing process, which must reliably be set even if + //! the process crashes before it’s able to establish its own annotations. + //! To interoperate with Breakpad servers, the recommended practice is to + //! specify values for the `"prod"` and `"ver"` keys as process + //! annotations. + //! \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 + //! minidump streams. `nullptr` if not required. + CrosCrashReportExceptionHandler( + CrashReportDatabase* database, + const std::map<std::string, std::string>* process_annotations, + const UserStreamDataSources* user_stream_data_sources); + + ~CrosCrashReportExceptionHandler() override; + + // ExceptionHandlerServer::Delegate: + + bool HandleException(pid_t client_process_id, + uid_t client_uid, + const ExceptionHandlerProtocol::ClientInformation& info, + VMAddress requesting_thread_stack_address = 0, + pid_t* requesting_thread_id = nullptr, + UUID* local_report_id = nullptr) override; + + bool HandleExceptionWithBroker( + pid_t client_process_id, + uid_t client_uid, + const ExceptionHandlerProtocol::ClientInformation& info, + int broker_sock, + UUID* local_report_id = nullptr) override; + + private: + bool HandleExceptionWithConnection( + PtraceConnection* connection, + const ExceptionHandlerProtocol::ClientInformation& info, + uid_t client_uid, + VMAddress requesting_thread_stack_address, + pid_t* requesting_thread_id, + UUID* local_report_id = nullptr); + + CrashReportDatabase* database_; // weak + const std::map<std::string, std::string>* process_annotations_; // weak + const UserStreamDataSources* user_stream_data_sources_; // weak + + DISALLOW_COPY_AND_ASSIGN(CrosCrashReportExceptionHandler); +}; + +} // namespace crashpad + +#endif // CRASHPAD_HANDLER_LINUX_CROS_CRASH_REPORT_EXCEPTION_HANDLER_H_ diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index 48dcf07b..ac430a4c 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -112,8 +112,7 @@ class ExceptionHandlerServer { int broker_sock, UUID* local_report_id = nullptr) = 0; - protected: - ~Delegate() {} + virtual ~Delegate() {} }; ExceptionHandlerServer(); diff --git a/handler/mac/crash_report_exception_handler.h b/handler/mac/crash_report_exception_handler.h index 0b44de67..b5a59e43 100644 --- a/handler/mac/crash_report_exception_handler.h +++ b/handler/mac/crash_report_exception_handler.h @@ -30,7 +30,8 @@ namespace crashpad { //! \brief An exception handler that writes crash reports for exception messages //! to a CrashReportDatabase. -class CrashReportExceptionHandler : public UniversalMachExcServer::Interface { +class CrashReportExceptionHandler final + : public UniversalMachExcServer::Interface { public: //! \brief Creates a new object that will store crash reports in \a database. //! diff --git a/handler/win/crash_report_exception_handler.h b/handler/win/crash_report_exception_handler.h index c2781de3..566f0472 100644 --- a/handler/win/crash_report_exception_handler.h +++ b/handler/win/crash_report_exception_handler.h @@ -31,7 +31,8 @@ class CrashReportUploadThread; //! \brief An exception handler that writes crash reports for exception messages //! to a CrashReportDatabase. -class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { +class CrashReportExceptionHandler final + : public ExceptionHandlerServer::Delegate { public: //! \brief Creates a new object that will store crash reports in \a database. //! diff --git a/util/file/file_io.h b/util/file/file_io.h index 7af47f85..3c956cc2 100644 --- a/util/file/file_io.h +++ b/util/file/file_io.h @@ -398,7 +398,7 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, FileWriteMode mode, FilePermissions permissions); -#if defined(OS_CHROMEOS) +#if defined(OS_LINUX) //! \brief Wraps memfd_create(), logging an error if the operation fails. //! Unlike other file open operations, this doesn't set `O_CLOEXEC`. //! @@ -409,7 +409,7 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, //! \sa LoggingOpenFileForWrite //! \sa LoggingOpenFileForReadAndWrite FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path); -#endif +#endif // OS_LINUX //! \brief Wraps OpenFileForReadAndWrite(), logging an error if the operation //! fails. diff --git a/util/file/file_io_posix.cc b/util/file/file_io_posix.cc index 03fc262e..b72a48eb 100644 --- a/util/file/file_io_posix.cc +++ b/util/file/file_io_posix.cc @@ -99,7 +99,7 @@ FileHandle OpenFileForOutput(int rdwr_or_wronly, permissions == FilePermissions::kWorldReadable ? 0644 : 0600)); } -#if defined(OS_CHROMEOS) +#if defined(OS_LINUX) FileHandle OpenMemFileForOutput(const base::FilePath& path) { return HANDLE_EINTR(memfd_create(path.value().c_str(), 0)); } @@ -156,7 +156,7 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, return fd; } -#if defined(OS_CHROMEOS) +#if defined(OS_LINUX) FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path) { FileHandle fd = OpenMemFileForOutput(path); PLOG_IF(ERROR, fd < 0) << "memfd_create " << path.value(); diff --git a/util/file/file_writer.cc b/util/file/file_writer.cc index 5f922429..de28575d 100644 --- a/util/file/file_writer.cc +++ b/util/file/file_writer.cc @@ -171,7 +171,7 @@ bool FileWriter::Open(const base::FilePath& path, return true; } -#if defined(OS_CHROMEOS) +#if defined(OS_LINUX) bool FileWriter::OpenMemfd(const base::FilePath& path) { CHECK(!file_.is_valid()); file_.reset(LoggingOpenMemFileForWrite(path)); diff --git a/util/file/file_writer.h b/util/file/file_writer.h index 1f9a0203..663adff1 100644 --- a/util/file/file_writer.h +++ b/util/file/file_writer.h @@ -131,7 +131,7 @@ class FileWriter : public FileWriterInterface { FileWriteMode write_mode, FilePermissions permissions); -#if defined(OS_CHROMEOS) +#if defined(OS_LINUX) //! \brief Wraps LoggingOpenMemFileForWrite(). //! //! \return `true` if the operation succeeded, `false` if it failed, with an diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index 85b2f23f..90688c73 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -51,7 +51,10 @@ class ExceptionHandlerProtocol { //! SanitizationInformation struct, or 0 if there is no such struct. VMAddress sanitization_information_address; -#if defined(OS_CHROMEOS) +#if defined(OS_LINUX) + //! \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`. uint64_t crash_loop_before_time; #endif }; From e1e55e224627a5e74d524f6395a3d1617368a564 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 3 Sep 2019 09:05:50 -0700 Subject: [PATCH 255/401] linux: initialize crash_loop_before_time member Change-Id: I8910d0700056232afb82afc4ef1463212053f7e2 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1782737 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/linux/exception_handler_protocol.cc | 7 ++++++- util/linux/exception_handler_protocol.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/util/linux/exception_handler_protocol.cc b/util/linux/exception_handler_protocol.cc index 628a4e12..45590c82 100644 --- a/util/linux/exception_handler_protocol.cc +++ b/util/linux/exception_handler_protocol.cc @@ -17,7 +17,12 @@ namespace crashpad { ExceptionHandlerProtocol::ClientInformation::ClientInformation() - : exception_information_address(0), sanitization_information_address(0) {} + : exception_information_address(0), + sanitization_information_address(0) +#if defined(OS_LINUX) + , crash_loop_before_time(0) +#endif // OS_LINUX +{} ExceptionHandlerProtocol::ClientToServerMessage::ClientToServerMessage() : version(kVersion), diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index 90688c73..7312b9d1 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -21,6 +21,7 @@ #include <sys/types.h> #include "base/macros.h" +#include "build/build_config.h" #include "util/file/file_io.h" #include "util/misc/address_types.h" From e3bf3a5fde918e342c7394b024b23832fdbd333e Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Tue, 3 Sep 2019 16:05:01 -0400 Subject: [PATCH 256/401] Roll crashpad/third_party/mini_chromium/mini_chromium/ 588976752..660b43a77 (2 commits) https://chromium.googlesource.com/chromium/mini_chromium/+log/5889767521ee..660b43a77989 $ git log 588976752..660b43a77 --date=short --no-merges --format='%ad %ae %s' 2019-09-03 rohitrao iOS build support. 2019-08-23 rohitrao Removes unnecessary semicolons from foundation_util. Created with: roll-dep crashpad/third_party/mini_chromium/mini_chromium Change-Id: I2a2f6312b8ad02356ab1e8c4ec524994558665b2 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1783163 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 46c34240..ec173470 100644 --- a/DEPS +++ b/DEPS @@ -33,7 +33,7 @@ deps = { '8048ece6c16c91acfe0d36d1d3cc0890ab6e945c', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '5889767521eed1483b5858b12c54893f21d72fd0', + '660b43a779892e7fdb74d490b54cf37ffe8a978d', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 9a62344612016876a9a1be4150192e77911e33f2 Mon Sep 17 00:00:00 2001 From: Tao Bai <michaelbai@chromium.org> Date: Thu, 5 Sep 2019 17:53:01 -0700 Subject: [PATCH 257/401] [Log minidump] OutputStream interface and zlib implementation This is the 1st patch for logging minidump in Android. it adds OutputStream interface and zlib implementation for output pipline. Bug: crashpad:308 Change-Id: I4738b8f223886049e6e259b9b25c00e5120156e5 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1745355 Commit-Queue: Tao Bai <michaelbai@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/BUILD.gn | 11 +- util/stream/output_stream_interface.h | 64 +++++++++ util/stream/test_output_stream.cc | 48 +++++++ util/stream/test_output_stream.h | 66 +++++++++ util/stream/zlib_output_stream.cc | 139 ++++++++++++++++++ util/stream/zlib_output_stream.h | 82 +++++++++++ util/stream/zlib_output_stream_test.cc | 186 +++++++++++++++++++++++++ 7 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 util/stream/output_stream_interface.h create mode 100644 util/stream/test_output_stream.cc create mode 100644 util/stream/test_output_stream.h create mode 100644 util/stream/zlib_output_stream.cc create mode 100644 util/stream/zlib_output_stream.h create mode 100644 util/stream/zlib_output_stream_test.cc diff --git a/util/BUILD.gn b/util/BUILD.gn index 3819b153..853b15bc 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -49,7 +49,8 @@ if (crashpad_is_mac) { if (!use_system_xcode) { import("//build/config/clang/clang.gni") import("//build/config/mac/mac_sdk.gni") - clang_path = rebase_path("$clang_base_path/bin/", root_build_dir) + "clang" + clang_path = + rebase_path("$clang_base_path/bin/", root_build_dir) + "clang" mig_path = "$mac_bin_path" + "mig" migcom_path = "$mac_bin_path" + "../libexec/migcom" @@ -165,6 +166,9 @@ static_library("util") { "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", @@ -177,6 +181,8 @@ static_library("util") { "thread/worker_thread.h", ] + defines = [ "ZLIB_CONST" ] + if (crashpad_is_posix || crashpad_is_fuchsia) { sources += [ "file/directory_reader_posix.cc", @@ -593,6 +599,9 @@ source_set("util_test") { "stdlib/strlcpy_test.cc", "stdlib/strnlen_test.cc", "stdlib/thread_safe_vector_test.cc", + "stream/test_output_stream.cc", + "stream/test_output_stream.h", + "stream/zlib_output_stream_test.cc", "string/split_string_test.cc", "synchronization/semaphore_test.cc", "thread/thread_log_messages_test.cc", diff --git a/util/stream/output_stream_interface.h b/util/stream/output_stream_interface.h new file mode 100644 index 00000000..397860ef --- /dev/null +++ b/util/stream/output_stream_interface.h @@ -0,0 +1,64 @@ +// 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_UTIL_STREAM_OUTPUT_STREAM_INTERFACE_H_ +#define CRASHPAD_UTIL_STREAM_OUTPUT_STREAM_INTERFACE_H_ + +#include <stddef.h> +#include <stdint.h> + +namespace crashpad { + +//! \brief The interface for an output stream pipeline. +//! +//! Example: +//! <code> +//! class OutputStreamInterfaceImpl : public OutputStreamInterface { +//! ... +//! }; +//! +//! // Create a OutputStream. +//! OutputStreamInterfaceImpl impl(...); +//! // Write the data multiple times. +//! while (has_data) { +//! impl.Write(data, size); +//! ... +//! } +//! // Flush internal buffer to indicate all data has been written. +//! impl.Flush(); +//! </code> +//! +class OutputStreamInterface { + public: + virtual ~OutputStreamInterface() = default; + + //! \brief Writes \a data to this stream. This method may be called multiple + //! times for streaming. + //! + //! \param[in] data The data that should be written. + //! \param[in] size The size of \a data. + //! + //! \return `true` on success. + virtual bool Write(const uint8_t* data, size_t size) = 0; + + //! \brief Flush the internal buffer after all data has been written. + //! + //! Write() can't be called afterwards. + //! \return `true` on success. + virtual bool Flush() = 0; +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_STREAM_OUTPUT_STREAM_INTERFACE_H_ diff --git a/util/stream/test_output_stream.cc b/util/stream/test_output_stream.cc new file mode 100644 index 00000000..04ef7007 --- /dev/null +++ b/util/stream/test_output_stream.cc @@ -0,0 +1,48 @@ +// 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. + +#include "util/stream/test_output_stream.h" +#include "base/logging.h" + +namespace crashpad { +namespace test { + +TestOutputStream::TestOutputStream() + : last_written_data_(), + all_data_(), + write_count_(0), + flush_count_(0), + flush_needed_(false) {} + +TestOutputStream::~TestOutputStream() { + DCHECK(!flush_needed_); +} + +bool TestOutputStream::Write(const uint8_t* data, size_t size) { + last_written_data_.assign(data, data + size); + all_data_.insert(all_data_.end(), data, data + size); + + flush_needed_ = true; + write_count_++; + return true; +} + +bool TestOutputStream::Flush() { + flush_needed_ = false; + flush_count_++; + return true; +} + +} // namespace test +} // namespace crashpad diff --git a/util/stream/test_output_stream.h b/util/stream/test_output_stream.h new file mode 100644 index 00000000..dcd0d45d --- /dev/null +++ b/util/stream/test_output_stream.h @@ -0,0 +1,66 @@ +// 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_UTIL_STREAM_TEST_OUTPUT_STREAM_H_ +#define CRASHPAD_UTIL_STREAM_TEST_OUTPUT_STREAM_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <vector> + +#include "base/macros.h" +#include "util/stream/output_stream_interface.h" + +namespace crashpad { +namespace test { + +//! \brief The help class for \a OutputStreamInterface related tests. +class TestOutputStream : public OutputStreamInterface { + public: + TestOutputStream(); + ~TestOutputStream() override; + + // OutputStreamInterface: + bool Write(const uint8_t* data, size_t size) override; + bool Flush() override; + + //! \return the data that has been received by the last call of Write(). + const std::vector<uint8_t>& last_written_data() const { + return last_written_data_; + } + + //! \return all data that has been received. + const std::vector<uint8_t>& all_data() const { return all_data_; } + + //! \return the number of times Write() has been called. + size_t write_count() const { return write_count_; } + + //! \return the number of times Flush() has been called. + size_t flush_count() const { return flush_count_; } + + private: + std::vector<uint8_t> last_written_data_; + std::vector<uint8_t> all_data_; + size_t write_count_; + size_t flush_count_; + bool flush_needed_; + + DISALLOW_COPY_AND_ASSIGN(TestOutputStream); +}; + +} // namespace test +} // namespace crashpad + +#endif // CRASHPAD_UTIL_STREAM_TEST_OUTPUT_STREAM_H_ diff --git a/util/stream/zlib_output_stream.cc b/util/stream/zlib_output_stream.cc new file mode 100644 index 00000000..88861db1 --- /dev/null +++ b/util/stream/zlib_output_stream.cc @@ -0,0 +1,139 @@ +// 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. + +#include "util/stream/zlib_output_stream.h" + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" +#include "base/stl_util.h" +#include "util/misc/zlib.h" + +namespace crashpad { + +ZlibOutputStream::ZlibOutputStream( + Mode mode, + std::unique_ptr<OutputStreamInterface> output_stream) + : output_stream_(std::move(output_stream)), + mode_(mode), + initialized_(), + flush_needed_(false) {} + +ZlibOutputStream::~ZlibOutputStream() { + if (!initialized_.is_valid()) + return; + DCHECK(!flush_needed_); + if (mode_ == Mode::kCompress) { + if (deflateEnd(&zlib_stream_) != Z_OK) + LOG(ERROR) << "deflateEnd: " << zlib_stream_.msg; + } else if (mode_ == Mode::kDecompress) { + if (inflateEnd(&zlib_stream_) != Z_OK) + LOG(ERROR) << "inflateEnd: " << zlib_stream_.msg; + } +} + +bool ZlibOutputStream::Write(const uint8_t* data, size_t size) { + if (initialized_.is_uninitialized()) { + initialized_.set_invalid(); + + zlib_stream_.zalloc = Z_NULL; + zlib_stream_.zfree = Z_NULL; + zlib_stream_.opaque = Z_NULL; + + if (mode_ == Mode::kDecompress) { + int result = inflateInit(&zlib_stream_); + if (result != Z_OK) { + LOG(ERROR) << "inflateInit: " << ZlibErrorString(result); + return false; + } + } else if (mode_ == Mode::kCompress) { + int result = deflateInit(&zlib_stream_, Z_BEST_COMPRESSION); + if (result != Z_OK) { + LOG(ERROR) << "deflateInit: " << ZlibErrorString(result); + return false; + } + } + zlib_stream_.next_out = buffer_; + zlib_stream_.avail_out = base::saturated_cast<uInt>(base::size(buffer_)); + initialized_.set_valid(); + } + + if (!initialized_.is_valid()) + return false; + + zlib_stream_.next_in = data; + zlib_stream_.avail_in = base::saturated_cast<uInt>(size); + flush_needed_ = false; + while (zlib_stream_.avail_in > 0) { + if (mode_ == Mode::kCompress) { + if (deflate(&zlib_stream_, Z_NO_FLUSH) != Z_OK) { + LOG(ERROR) << "deflate: " << zlib_stream_.msg; + return false; + } + } else if (mode_ == Mode::kDecompress) { + int result = inflate(&zlib_stream_, Z_NO_FLUSH); + if (result == Z_STREAM_END) { + if (zlib_stream_.avail_in > 0) { + LOG(ERROR) << "inflate: unconsumed input"; + return false; + } + } else if (result != Z_OK) { + LOG(ERROR) << "inflate: " << zlib_stream_.msg; + return false; + } + } + + if (!WriteOutputStream()) + return false; + } + flush_needed_ = true; + return true; +} + +bool ZlibOutputStream::Flush() { + if (initialized_.is_valid() && flush_needed_) { + flush_needed_ = false; + int result = Z_OK; + do { + if (mode_ == Mode::kCompress) { + result = deflate(&zlib_stream_, Z_FINISH); + if (result != Z_STREAM_END && result != Z_BUF_ERROR && result != Z_OK) { + LOG(ERROR) << "deflate: " << zlib_stream_.msg; + return false; + } + } else if (mode_ == Mode::kDecompress) { + result = inflate(&zlib_stream_, Z_FINISH); + if (result != Z_STREAM_END && result != Z_BUF_ERROR && result != Z_OK) { + LOG(ERROR) << "inflate: " << zlib_stream_.msg; + return false; + } + } + if (!WriteOutputStream()) + return false; + } while (result != Z_STREAM_END); + } + return output_stream_->Flush(); +} + +bool ZlibOutputStream::WriteOutputStream() { + auto valid_size = base::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<uInt>(base::size(buffer_)); + + return true; +} + +} // namespace crashpad diff --git a/util/stream/zlib_output_stream.h b/util/stream/zlib_output_stream.h new file mode 100644 index 00000000..d8e62a6c --- /dev/null +++ b/util/stream/zlib_output_stream.h @@ -0,0 +1,82 @@ +// 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_UTIL_STREAM_ZLIB_OUTPUT_STREAM_H_ +#define CRASHPAD_UTIL_STREAM_ZLIB_OUTPUT_STREAM_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> + +#include "base/macros.h" +#include "third_party/zlib/zlib_crashpad.h" +#include "util/misc/initialization_state.h" +#include "util/stream/output_stream_interface.h" + +namespace crashpad { + +//! \brief The class wraps zlib into \a OutputStreamInterface. +class ZlibOutputStream : public OutputStreamInterface { + public: + //! \brief Whether this object is configured to compress or decompress data. + enum class Mode : bool { + //! \brief Data passed through this object is compressed. + kCompress = false, + //! \brief Data passed through this object is decompressed. + kDecompress = true + }; + + //! \param[in] mode The work mode of this object. + //! \param[in] output_stream The output_stream that this object writes to. + //! + //! To construct an output pipeline, the output stream needs an output stream + //! to write the result to. For example, the code below constructs a + //! compress->base94-encoding->log output stream pipline. + //! + //! <code> + //! ZlibOutputStream zlib_output_stream( + //! ZlibOutputStream::Mode::kDeflate, + //! std::make_unique<Base94OutputStream>( + //! Base94OutputStream::Mode::kEncode, + //! std::make_unique<LogOutputStream>())); + //! </code> + //! + //! + ZlibOutputStream(Mode mode, + std::unique_ptr<OutputStreamInterface> output_stream); + ~ZlibOutputStream() override; + + // OutputStreamInterface: + bool Write(const uint8_t* data, size_t size) override; + bool Flush() override; + + private: + // Write compressed/decompressed data to |output_stream_| and empty the output + // buffer in |zlib_stream_|. + bool WriteOutputStream(); + + uint8_t buffer_[4096]; + z_stream zlib_stream_; + std::unique_ptr<OutputStreamInterface> output_stream_; + Mode mode_; + InitializationState initialized_; // protects zlib_stream_ + bool flush_needed_; + + DISALLOW_COPY_AND_ASSIGN(ZlibOutputStream); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_STREAM_ZLIB_OUTPUT_STREAM_H_ diff --git a/util/stream/zlib_output_stream_test.cc b/util/stream/zlib_output_stream_test.cc new file mode 100644 index 00000000..dfa935b6 --- /dev/null +++ b/util/stream/zlib_output_stream_test.cc @@ -0,0 +1,186 @@ +// 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. + +#include "util/stream/zlib_output_stream.h" + +#include <string.h> + +#include <algorithm> + +#include "base/rand_util.h" +#include "base/stl_util.h" +#include "base/strings/stringprintf.h" +#include "gtest/gtest.h" +#include "util/stream/test_output_stream.h" + +namespace crashpad { +namespace test { +namespace { + +constexpr size_t kShortDataLength = 10; +constexpr size_t kLongDataLength = 4096 * 10; + +class ZlibOutputStreamTest : public testing::Test { + public: + ZlibOutputStreamTest() : input_(), deterministic_input_() { + auto test_output_stream = std::make_unique<TestOutputStream>(); + test_output_stream_ = test_output_stream.get(); + zlib_output_stream_ = std::make_unique<ZlibOutputStream>( + ZlibOutputStream::Mode::kCompress, + std::make_unique<ZlibOutputStream>(ZlibOutputStream::Mode::kDecompress, + std::move(test_output_stream))); + } + + const uint8_t* BuildDeterministicInput(size_t size) { + deterministic_input_ = std::make_unique<uint8_t[]>(size); + uint8_t* deterministic_input_base = deterministic_input_.get(); + while (size-- > 0) + deterministic_input_base[size] = static_cast<uint8_t>(size); + return deterministic_input_base; + } + + const uint8_t* BuildRandomInput(size_t size) { + input_ = std::make_unique<uint8_t[]>(size); + base::RandBytes(&input_[0], size); + return input_.get(); + } + + const TestOutputStream& test_output_stream() const { + return *test_output_stream_; + } + + ZlibOutputStream* zlib_output_stream() const { + return zlib_output_stream_.get(); + } + + private: + std::unique_ptr<ZlibOutputStream> zlib_output_stream_; + std::unique_ptr<uint8_t[]> input_; + std::unique_ptr<uint8_t[]> deterministic_input_; + TestOutputStream* test_output_stream_; // weak, owned by zlib_output_stream_ + + DISALLOW_COPY_AND_ASSIGN(ZlibOutputStreamTest); +}; + +TEST_F(ZlibOutputStreamTest, WriteDeterministicShortData) { + const uint8_t* input = BuildDeterministicInput(kShortDataLength); + EXPECT_TRUE(zlib_output_stream()->Write(input, kShortDataLength)); + EXPECT_TRUE(zlib_output_stream()->Flush()); + EXPECT_EQ(test_output_stream().last_written_data().size(), kShortDataLength); + EXPECT_EQ(memcmp(test_output_stream().last_written_data().data(), + input, + kShortDataLength), + 0); +} + +TEST_F(ZlibOutputStreamTest, WriteDeterministicLongDataOneTime) { + const uint8_t* input = BuildDeterministicInput(kLongDataLength); + EXPECT_TRUE(zlib_output_stream()->Write(input, kLongDataLength)); + EXPECT_TRUE(zlib_output_stream()->Flush()); + EXPECT_EQ(test_output_stream().all_data().size(), kLongDataLength); + EXPECT_EQ( + memcmp(test_output_stream().all_data().data(), input, kLongDataLength), + 0); +} + +TEST_F(ZlibOutputStreamTest, WriteDeterministicLongDataMultipleTimes) { + const uint8_t* input = BuildDeterministicInput(kLongDataLength); + + static constexpr size_t kWriteLengths[] = { + 4, 96, 40, kLongDataLength - 4 - 96 - 40}; + + size_t offset = 0; + for (size_t index = 0; index < base::size(kWriteLengths); ++index) { + const size_t write_length = kWriteLengths[index]; + SCOPED_TRACE(base::StringPrintf( + "offset %zu, write_length %zu", offset, write_length)); + EXPECT_TRUE(zlib_output_stream()->Write(input + offset, write_length)); + offset += write_length; + } + EXPECT_TRUE(zlib_output_stream()->Flush()); + EXPECT_EQ(test_output_stream().all_data().size(), kLongDataLength); + EXPECT_EQ( + memcmp(test_output_stream().all_data().data(), input, kLongDataLength), + 0); +} + +TEST_F(ZlibOutputStreamTest, WriteShortData) { + const uint8_t* input = BuildRandomInput(kShortDataLength); + EXPECT_TRUE(zlib_output_stream()->Write(input, kShortDataLength)); + EXPECT_TRUE(zlib_output_stream()->Flush()); + EXPECT_EQ(memcmp(test_output_stream().last_written_data().data(), + input, + kShortDataLength), + 0); + EXPECT_EQ(test_output_stream().last_written_data().size(), kShortDataLength); +} + +TEST_F(ZlibOutputStreamTest, WriteLongDataOneTime) { + const uint8_t* input = BuildRandomInput(kLongDataLength); + EXPECT_TRUE(zlib_output_stream()->Write(input, kLongDataLength)); + EXPECT_TRUE(zlib_output_stream()->Flush()); + EXPECT_EQ(test_output_stream().all_data().size(), kLongDataLength); + EXPECT_EQ( + memcmp(test_output_stream().all_data().data(), input, kLongDataLength), + 0); +} + +TEST_F(ZlibOutputStreamTest, WriteLongDataMultipleTimes) { + const uint8_t* input = BuildRandomInput(kLongDataLength); + + // Call Write() a random number of times. + size_t index = 0; + while (index < kLongDataLength) { + size_t write_length = + std::min(static_cast<size_t>(base::RandInt(0, 4096 * 2)), + kLongDataLength - index); + SCOPED_TRACE( + base::StringPrintf("index %zu, write_length %zu", index, write_length)); + EXPECT_TRUE(zlib_output_stream()->Write(input + index, write_length)); + index += write_length; + } + EXPECT_TRUE(zlib_output_stream()->Flush()); + EXPECT_EQ(test_output_stream().all_data().size(), kLongDataLength); + EXPECT_EQ( + memcmp(test_output_stream().all_data().data(), input, kLongDataLength), + 0); +} + +TEST_F(ZlibOutputStreamTest, NoWriteOrFlush) { + EXPECT_EQ(test_output_stream().write_count(), 0u); + EXPECT_EQ(test_output_stream().flush_count(), 0u); + EXPECT_TRUE(test_output_stream().all_data().empty()); +} + +TEST_F(ZlibOutputStreamTest, FlushWithoutWrite) { + EXPECT_TRUE(zlib_output_stream()->Flush()); + EXPECT_EQ(test_output_stream().write_count(), 0u); + EXPECT_EQ(test_output_stream().flush_count(), 1u); + EXPECT_TRUE(test_output_stream().all_data().empty()); +} + +TEST_F(ZlibOutputStreamTest, WriteEmptyData) { + std::vector<uint8_t> empty_data; + EXPECT_TRUE(zlib_output_stream()->Write( + static_cast<const uint8_t*>(empty_data.data()), empty_data.size())); + EXPECT_TRUE(zlib_output_stream()->Flush()); + EXPECT_TRUE(zlib_output_stream()->Flush()); + EXPECT_EQ(test_output_stream().write_count(), 0u); + EXPECT_EQ(test_output_stream().flush_count(), 2u); + EXPECT_TRUE(test_output_stream().all_data().empty()); +} + +} // namespace +} // namespace test +} // namespace crashpad From 9b314d5fa819f0f418889ddf0ac36aa04b42a7cb Mon Sep 17 00:00:00 2001 From: Tim Zheng <timzheng@google.com> Date: Mon, 9 Sep 2019 14:55:20 -0700 Subject: [PATCH 258/401] cros: Pass a dir for minidumps to crash_reporter This change add function to pass a file directory to Chrome OS's crash_reporter to write minidumps to. This is used for tests. BUG=chromium:944123 Change-Id: Ia61955d5ec671c61adde14e61dc72e4be32e389f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1775290 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- handler/handler_main.cc | 19 +++++++++++++++++++ .../cros_crash_report_exception_handler.cc | 4 ++++ .../cros_crash_report_exception_handler.h | 2 ++ 3 files changed, 25 insertions(+) diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 7b69e848..ba0d57e9 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -163,6 +163,8 @@ void Usage(const base::FilePath& me) { " only if uploads are enabled for the database\n" #if defined(OS_CHROMEOS) " --use-cros-crash-reporter\n" +" --minidump-dir-for-tests=TEST_MINIDUMP_DIR\n" +" the directory for testing minidumps\n" #endif // OS_CHROMEOS " --help display this help and exit\n" " --version output version information and exit\n", @@ -197,6 +199,7 @@ struct Options { bool upload_gzip; #if defined(OS_CHROMEOS) bool use_cros_crash_reporter; + base::FilePath minidump_dir_for_tests; #endif // OS_CHROMEOS }; @@ -571,6 +574,7 @@ int HandlerMain(int argc, kOptionURL, #if defined(OS_CHROMEOS) kOptionUseCrosCrashReporter, + kOptionMinidumpDirForTests, #endif // OS_CHROMEOS // Standard options. @@ -642,6 +646,10 @@ int HandlerMain(int argc, no_argument, nullptr, kOptionUseCrosCrashReporter}, + {"minidump_dir_for_tests", + required_argument, + nullptr, + kOptionMinidumpDirForTests}, #endif // OS_CHROMEOS {"help", no_argument, nullptr, kOptionHelp}, {"version", no_argument, nullptr, kOptionVersion}, @@ -789,6 +797,11 @@ int HandlerMain(int argc, options.use_cros_crash_reporter = true; break; } + case kOptionMinidumpDirForTests: { + options.minidump_dir_for_tests = base::FilePath( + ToolSupport::CommandLineArgumentToFilePathStringType(optarg)); + break; + } #endif // OS_CHROMEOS case kOptionHelp: { Usage(me); @@ -946,6 +959,12 @@ int HandlerMain(int argc, user_stream_sources); #endif // OS_CHROMEOS +#if defined(OS_CHROMEOS) + if (!options.minidump_dir_for_tests.empty()) { + exception_handler->SetDumpDir(options.minidump_dir_for_tests); + } +#endif + #if defined(OS_LINUX) || defined(OS_ANDROID) if (options.exception_information_address) { ExceptionHandlerProtocol::ClientInformation info; diff --git a/handler/linux/cros_crash_report_exception_handler.cc b/handler/linux/cros_crash_report_exception_handler.cc index a24b17f6..f54cc07c 100644 --- a/handler/linux/cros_crash_report_exception_handler.cc +++ b/handler/linux/cros_crash_report_exception_handler.cc @@ -255,6 +255,9 @@ bool CrosCrashReportExceptionHandler::HandleExceptionWithConnection( argv.push_back("--crash_loop_before=" + std::to_string(info.crash_loop_before_time)); } + if (!dump_dir_.empty()) { + argv.push_back("--chrome_dump_dir=" + dump_dir_.value()); + } if (!DoubleForkAndExec(argv, nullptr /* envp */, @@ -270,6 +273,7 @@ bool CrosCrashReportExceptionHandler::HandleExceptionWithConnection( if (local_report_id != nullptr) { *local_report_id = uuid; } + LOG(INFO) << "Successfully wrote report " << uuid.ToString(); Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess); return true; diff --git a/handler/linux/cros_crash_report_exception_handler.h b/handler/linux/cros_crash_report_exception_handler.h index f6ca445b..def1c82b 100644 --- a/handler/linux/cros_crash_report_exception_handler.h +++ b/handler/linux/cros_crash_report_exception_handler.h @@ -76,6 +76,7 @@ class CrosCrashReportExceptionHandler int broker_sock, UUID* local_report_id = nullptr) override; + void SetDumpDir(const base::FilePath& dump_dir) { dump_dir_ = dump_dir; } private: bool HandleExceptionWithConnection( PtraceConnection* connection, @@ -88,6 +89,7 @@ class CrosCrashReportExceptionHandler CrashReportDatabase* database_; // weak const std::map<std::string, std::string>* process_annotations_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak + base::FilePath dump_dir_; DISALLOW_COPY_AND_ASSIGN(CrosCrashReportExceptionHandler); }; From fc44a3747cf596be25ef0d6ee2c69d1f9dcad143 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 9 Sep 2019 14:07:42 -0700 Subject: [PATCH 259/401] linux: Allow configuring unhandled signals Change-Id: I621555f892a3064c5cba09120309bc900da237f9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1793563 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client.h | 21 ++++++++++++++++---- client/crashpad_client_linux.cc | 35 +++++++++++++++++++-------------- util/posix/signals.cc | 16 +++++++++++---- util/posix/signals.h | 12 ++++++++--- util/posix/signals_test.cc | 7 ++++++- 5 files changed, 64 insertions(+), 27 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 36c9d1f8..f357ca01 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -16,6 +16,7 @@ #define CRASHPAD_CLIENT_CRASHPAD_CLIENT_H_ #include <map> +#include <set> #include <string> #include <vector> @@ -138,7 +139,7 @@ class CrashpadClient { //! this process' ptracer. 0 indicates it is not necessary to set the //! handler as this process' ptracer. -1 indicates that the handler's //! process ID should be determined by communicating over the socket. - static bool SetHandlerSocket(ScopedFileHandle sock, pid_t pid); + bool SetHandlerSocket(ScopedFileHandle sock, pid_t pid); #endif // OS_ANDROID || OS_LINUX || DOXYGEN #if defined(OS_ANDROID) || DOXYGEN @@ -170,7 +171,7 @@ class CrashpadClient { //! specified in this parameter. //! //! \return `true` on success, `false` on failure with a message logged. - static bool StartJavaHandlerAtCrash( + bool StartJavaHandlerAtCrash( const std::string& class_name, const std::vector<std::string>* env, const base::FilePath& database, @@ -251,7 +252,7 @@ class CrashpadClient { //! specified in this parameter. //! //! \return `true` on success, `false` on failure with a message logged. - static bool StartHandlerWithLinkerAtCrash( + bool StartHandlerWithLinkerAtCrash( const std::string& handler_trampoline, const std::string& handler_library, bool is_64_bit, @@ -333,7 +334,7 @@ class CrashpadClient { //! specified in this parameter. //! //! \return `true` on success, `false` on failure with a message logged. - static bool StartHandlerAtCrash( + bool StartHandlerAtCrash( const base::FilePath& handler, const base::FilePath& database, const base::FilePath& metrics_dir, @@ -413,6 +414,16 @@ class CrashpadClient { //! \param[in] handler The custom crash signal handler to install. static void SetFirstChanceExceptionHandler(FirstChanceHandler handler); + //! \brief Configures a set of signals that shouldn't have Crashpad signal + //! handlers installed. + //! + //! This method should be called before calling StartHandler(), + //! SetHandlerSocket(), or other methods that install Crashpad signal + //! handlers. + //! + //! \param[in] unhandled_signals The set of unhandled signals + void SetUnhandledSignals(const std::set<int>& unhandled_signals); + #endif // OS_LINUX || OS_ANDROID || DOXYGEN #if defined(OS_MACOSX) || DOXYGEN @@ -604,6 +615,8 @@ class CrashpadClient { #elif defined(OS_WIN) std::wstring ipc_pipe_; ScopedKernelHANDLE handler_start_thread_; +#elif defined(OS_LINUX) + std::set<int> unhandled_signals_; #endif // OS_MACOSX DISALLOW_COPY_AND_ASSIGN(CrashpadClient); diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index eb210a28..c3ebbd4c 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -155,11 +155,11 @@ class SignalHandler { protected: SignalHandler() = default; - bool Install() { + bool Install(const std::set<int>* unhandled_signals) { DCHECK(!handler_); handler_ = this; return Signals::InstallCrashHandlers( - HandleOrReraiseSignal, 0, &old_actions_); + HandleOrReraiseSignal, 0, &old_actions_, unhandled_signals); } const ExceptionInformation& GetExceptionInfo() { @@ -202,7 +202,8 @@ class LaunchAtCrashHandler : public SignalHandler { } bool Initialize(std::vector<std::string>* argv_in, - const std::vector<std::string>* envp) { + const std::vector<std::string>* envp, + const std::set<int>* unhandled_signals) { argv_strings_.swap(*argv_in); if (envp) { @@ -215,7 +216,7 @@ class LaunchAtCrashHandler : public SignalHandler { &GetExceptionInfo())); StringVectorToCStringVector(argv_strings_, &argv_); - return Install(); + return Install(unhandled_signals); } void HandleCrashImpl() override { @@ -270,7 +271,9 @@ class RequestCrashDumpHandler : public SignalHandler { // created the namespace. // pid > 0 directly indicates what the handler's pid is expected to be, so // retrieving this information from the handler is not necessary. - bool Initialize(ScopedFileHandle sock, pid_t pid) { + bool Initialize(ScopedFileHandle sock, + pid_t pid, + const std::set<int>* unhandled_signals) { ExceptionHandlerClient client(sock.get(), true); if (pid < 0) { ucred creds; @@ -285,7 +288,7 @@ class RequestCrashDumpHandler : public SignalHandler { } sock_to_handler_.reset(sock.release()); handler_pid_ = pid; - return Install(); + return Install(unhandled_signals); } bool GetHandlerSocket(int* sock, pid_t* pid) { @@ -368,7 +371,8 @@ bool CrashpadClient::StartHandler( } auto signal_handler = RequestCrashDumpHandler::Get(); - return signal_handler->Initialize(std::move(client_sock), -1); + return signal_handler->Initialize( + std::move(client_sock), -1, &unhandled_signals_); } #if defined(OS_ANDROID) || defined(OS_LINUX) @@ -378,16 +382,14 @@ bool CrashpadClient::GetHandlerSocket(int* sock, pid_t* pid) { return signal_handler->GetHandlerSocket(sock, pid); } -// static bool CrashpadClient::SetHandlerSocket(ScopedFileHandle sock, pid_t pid) { auto signal_handler = RequestCrashDumpHandler::Get(); - return signal_handler->Initialize(std::move(sock), pid); + return signal_handler->Initialize(std::move(sock), pid, &unhandled_signals_); } #endif // OS_ANDROID || OS_LINUX #if defined(OS_ANDROID) -// static bool CrashpadClient::StartJavaHandlerAtCrash( const std::string& class_name, const std::vector<std::string>* env, @@ -405,7 +407,7 @@ bool CrashpadClient::StartJavaHandlerAtCrash( kInvalidFileHandle); auto signal_handler = LaunchAtCrashHandler::Get(); - return signal_handler->Initialize(&argv, env); + return signal_handler->Initialize(&argv, env, &unhandled_signals_); } // static @@ -423,7 +425,6 @@ bool CrashpadClient::StartJavaHandlerForClient( return DoubleForkAndExec(argv, env, socket, false, nullptr); } -// static bool CrashpadClient::StartHandlerWithLinkerAtCrash( const std::string& handler_trampoline, const std::string& handler_library, @@ -445,7 +446,7 @@ bool CrashpadClient::StartHandlerWithLinkerAtCrash( arguments, kInvalidFileHandle); auto signal_handler = LaunchAtCrashHandler::Get(); - return signal_handler->Initialize(&argv, env); + return signal_handler->Initialize(&argv, env, &unhandled_signals_); } // static @@ -475,7 +476,6 @@ bool CrashpadClient::StartHandlerWithLinkerForClient( #endif -// static bool CrashpadClient::StartHandlerAtCrash( const base::FilePath& handler, const base::FilePath& database, @@ -487,7 +487,7 @@ bool CrashpadClient::StartHandlerAtCrash( handler, database, metrics_dir, url, annotations, arguments); auto signal_handler = LaunchAtCrashHandler::Get(); - return signal_handler->Initialize(&argv, nullptr); + return signal_handler->Initialize(&argv, nullptr, &unhandled_signals_); } // static @@ -543,6 +543,11 @@ void CrashpadClient::SetFirstChanceExceptionHandler( SignalHandler::Get()->SetFirstChanceHandler(handler); } +void CrashpadClient::SetUnhandledSignals(const std::set<int>& signals) { + DCHECK(!SignalHandler::Get()); + unhandled_signals_ = signals; +} + #if defined(OS_CHROMEOS) // static void CrashpadClient::SetCrashLoopBefore(uint64_t crash_loop_before_time) { diff --git a/util/posix/signals.cc b/util/posix/signals.cc index 1384de1e..53c10389 100644 --- a/util/posix/signals.cc +++ b/util/posix/signals.cc @@ -93,9 +93,14 @@ constexpr int kTerminateSignals[] = { bool InstallHandlers(const std::vector<int>& signals, Signals::Handler handler, int flags, - Signals::OldActions* old_actions) { + Signals::OldActions* old_actions, + const std::set<int>* unhandled_signals) { bool success = true; for (int sig : signals) { + if (unhandled_signals && + unhandled_signals->find(sig) != unhandled_signals->end()) { + continue; + } success &= Signals::InstallHandler( sig, handler, @@ -151,13 +156,15 @@ bool Signals::InstallDefaultHandler(int sig) { // static bool Signals::InstallCrashHandlers(Handler handler, int flags, - OldActions* old_actions) { + OldActions* old_actions, + const std::set<int>* unhandled_signals) { return InstallHandlers( std::vector<int>(kCrashSignals, kCrashSignals + base::size(kCrashSignals)), handler, flags, - old_actions); + old_actions, + unhandled_signals); } // static @@ -169,7 +176,8 @@ bool Signals::InstallTerminateHandlers(Handler handler, kTerminateSignals + base::size(kTerminateSignals)), handler, flags, - old_actions); + old_actions, + nullptr); } // static diff --git a/util/posix/signals.h b/util/posix/signals.h index dc550594..368161bf 100644 --- a/util/posix/signals.h +++ b/util/posix/signals.h @@ -17,6 +17,8 @@ #include <signal.h> +#include <set> + #include "base/macros.h" namespace crashpad { @@ -114,15 +116,19 @@ class Signals { //! the new action. May be `nullptr` if not needed. The same \a //! old_actions object may be used for calls to both this function and //! InstallTerminateHandlers(). + //! \param[in] unhandled_signals Signal handlers will not be installed for + //! signal numbers in this set. Optional. //! //! \return `true` on success. `false` on failure with a message logged. //! //! \warning This function may not be called from a signal handler because of //! its use of logging. See RestoreHandlerAndReraiseSignalOnReturn() //! instead. - static bool InstallCrashHandlers(Handler handler, - int flags, - OldActions* old_actions); + static bool InstallCrashHandlers( + Handler handler, + int flags, + OldActions* old_actions, + const std::set<int>* unhandled_signals = nullptr); //! \brief Installs a new signal handler for all signals associated with //! termination. diff --git a/util/posix/signals_test.cc b/util/posix/signals_test.cc index d91e3cc6..f46e331e 100644 --- a/util/posix/signals_test.cc +++ b/util/posix/signals_test.cc @@ -258,7 +258,12 @@ class SignalsTest : public Multiprocess { void MultiprocessChild() override { bool (*install_handlers)(Signals::Handler, int, Signals::OldActions*); if (Signals::IsCrashSignal(sig_)) { - install_handlers = Signals::InstallCrashHandlers; + install_handlers = [](Signals::Handler handler, + int sig, + Signals::OldActions* old_actions) { + return Signals::InstallCrashHandlers( + handler, sig, old_actions, nullptr); + }; } else if (Signals::IsTerminateSignal(sig_)) { install_handlers = Signals::InstallTerminateHandlers; } else { From abeccef1efdb7bcab90b05d5447770f9369e7967 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 10 Sep 2019 14:43:56 -0700 Subject: [PATCH 260/401] [fuchsia] fix crashpad_use_boringssl_for_http_transport_socket path * https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1745355/17/util/BUILD.gn#184 defines "defines" earlier in the target * this only affects Fuchsia in the Fuchsia tree, not the Crashpad tree TESTED=`fx build` in Fuchsia tree Change-Id: I5ac454828f958d6de4e4c6788d7c9a31408dc732 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1796964 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- util/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index 853b15bc..dec7d5c4 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -279,7 +279,7 @@ static_library("util") { if (crashpad_is_linux || crashpad_is_fuchsia || crashpad_is_android) { 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_fuchsia) { deps += [ "//third_party/boringssl" ] From 06fdbdecdc5d94989543bcec197752fdea2fbd9d Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 11 Sep 2019 10:37:54 -0700 Subject: [PATCH 261/401] android, chromeos: fix build breakages Also augment some documentation. Change-Id: Icbb8bdbe435484346f2b24e37f81182a3f189cb5 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1797189 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client.h | 2 +- handler/crashpad_handler.md | 7 +++++++ handler/handler_main.cc | 19 +++++++++++-------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index f357ca01..dfe13538 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -615,7 +615,7 @@ class CrashpadClient { #elif defined(OS_WIN) std::wstring ipc_pipe_; ScopedKernelHANDLE handler_start_thread_; -#elif defined(OS_LINUX) +#elif defined(OS_LINUX) || defined(OS_ANDROID) std::set<int> unhandled_signals_; #endif // OS_MACOSX diff --git a/handler/crashpad_handler.md b/handler/crashpad_handler.md index c4126b62..f7e63a50 100644 --- a/handler/crashpad_handler.md +++ b/handler/crashpad_handler.md @@ -279,6 +279,13 @@ establish the Crashpad client environment before running a program. library, typically in response to a user requesting this behavior. If this option is not specified, this program will behave as if uploads are disabled. + * **--use-cros-crash-reporter** + + Causes crash reports to be passed via an in-memory file to + `/sbin/crash_reporter` instead of storing them in the database. The database + is still used for Crashpad settings. This option is only valid on Chromium + OS. + * **--help** Display help and exit. diff --git a/handler/handler_main.cc b/handler/handler_main.cc index ba0d57e9..d5a9e609 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -163,8 +163,11 @@ void Usage(const base::FilePath& me) { " only if uploads are enabled for the database\n" #if defined(OS_CHROMEOS) " --use-cros-crash-reporter\n" +" pass crash reports to /sbin/crash_reporter\n" +" instead of storing them in the database\n" " --minidump-dir-for-tests=TEST_MINIDUMP_DIR\n" -" the directory for testing minidumps\n" +" causes /sbin/crash_reporter to leave dumps in\n" +" this directory instead of the normal location\n" #endif // OS_CHROMEOS " --help display this help and exit\n" " --version output version information and exit\n", @@ -936,10 +939,16 @@ int HandlerMain(int argc, #if defined(OS_CHROMEOS) if (options.use_cros_crash_reporter) { - exception_handler = std::make_unique<CrosCrashReportExceptionHandler>( + auto cros_handler = std::make_unique<CrosCrashReportExceptionHandler>( database.get(), &options.annotations, user_stream_sources); + + if (!options.minidump_dir_for_tests.empty()) { + cros_handler->SetDumpDir(options.minidump_dir_for_tests); + } + + exception_handler = std::move(cros_handler); } else { exception_handler = std::make_unique<CrashReportExceptionHandler>( database.get(), @@ -959,12 +968,6 @@ int HandlerMain(int argc, user_stream_sources); #endif // OS_CHROMEOS -#if defined(OS_CHROMEOS) - if (!options.minidump_dir_for_tests.empty()) { - exception_handler->SetDumpDir(options.minidump_dir_for_tests); - } -#endif - #if defined(OS_LINUX) || defined(OS_ANDROID) if (options.exception_information_address) { ExceptionHandlerProtocol::ClientInformation info; From e97cf7b29c16f6304d6461378ca0683f0afd566b Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 11 Sep 2019 11:30:22 -0700 Subject: [PATCH 262/401] update gyp_crashpad_android.py This patch updates gyp_crashpad_android.py to function with NDK r20, removes the requirement to generate a standalone toolchain, and updates documentation on building for Android. Also some gyp build fixes. Change-Id: Ide338417ab2a21eca7a4bf42c1fb834e5639c186 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1798746 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- build/gyp_crashpad_android.py | 87 ++++++++++------------------------- doc/developing.md | 56 ++++++---------------- handler/handler.gyp | 2 + util/util.gyp | 4 +- util/util_test.gyp | 2 +- 5 files changed, 44 insertions(+), 107 deletions(-) diff --git a/build/gyp_crashpad_android.py b/build/gyp_crashpad_android.py index f78c05b9..e17e7a26 100755 --- a/build/gyp_crashpad_android.py +++ b/build/gyp_crashpad_android.py @@ -28,82 +28,45 @@ def main(args): parser = argparse.ArgumentParser( description='Set up an Android cross build', epilog='Additional arguments will be passed to gyp_crashpad.py.') + parser.add_argument('--arch', required=True, help='Target architecture') + parser.add_argument('--api-level', required=True, help='Target API level') parser.add_argument('--ndk', required=True, help='Standalone NDK toolchain') - parser.add_argument('--compiler', - default='clang', - choices=('clang', 'gcc'), - help='The compiler to use, clang by default') (parsed, extra_command_line_args) = parser.parse_known_args(args) - NDK_ERROR=( - 'NDK must be a valid standalone NDK toolchain.\n' + - 'See https://developer.android.com/ndk/guides/standalone_toolchain.html') - arch_dirs = glob.glob(os.path.join(parsed.ndk, '*-linux-android*')) - if len(arch_dirs) != 1: - parser.error(NDK_ERROR) + ndk_bin_dir = os.path.join(parsed.ndk, + 'toolchains', + 'llvm', + 'prebuilt', + 'linux-x86_64', + 'bin') + if not os.path.exists(ndk_bin_dir): + parser.error("missing toolchain") - arch_triplet = os.path.basename(arch_dirs[0]) - ARCH_TRIPLET_TO_ARCH = { - 'arm-linux-androideabi': 'arm', - 'aarch64-linux-android': 'arm64', - 'i686-linux-android': 'ia32', - 'x86_64-linux-android': 'x64', - 'mipsel-linux-android': 'mips', - 'mips64el-linux-android': 'mips64', + ARCH_TO_ARCH_TRIPLET = { + 'arm': 'armv7a-linux-androideabi', + 'arm64': 'aarch64-linux-android', + 'ia32': 'i686-linux-android', + 'x64': 'x86_64-linux-android', } - if arch_triplet not in ARCH_TRIPLET_TO_ARCH: - parser.error(NDK_ERROR) - arch = ARCH_TRIPLET_TO_ARCH[arch_triplet] - ndk_bin_dir = os.path.join(parsed.ndk, 'bin') + clang_prefix = ARCH_TO_ARCH_TRIPLET[parsed.arch] + parsed.api_level + os.environ['CC_target'] = os.path.join(ndk_bin_dir, clang_prefix + '-clang') + os.environ['CXX_target'] = os.path.join(ndk_bin_dir, clang_prefix + '-clang++') - clang_path = os.path.join(ndk_bin_dir, 'clang') - extra_args = [] + extra_args = ['-D', 'android_api_level=' + parsed.api_level] - if parsed.compiler == 'clang': - os.environ['CC_target'] = clang_path - os.environ['CXX_target'] = os.path.join(ndk_bin_dir, 'clang++') - elif parsed.compiler == 'gcc': - os.environ['CC_target'] = os.path.join(ndk_bin_dir, - '%s-gcc' % arch_triplet) - os.environ['CXX_target'] = os.path.join(ndk_bin_dir, - '%s-g++' % arch_triplet) - - # Unlike the Clang build, when using GCC with unified headers, __ANDROID_API__ - # isn’t set automatically and must be pushed in to the build. Fish the correct - # value out of the Clang wrapper script. If deprecated headers are in use, the - # Clang wrapper won’t mention __ANDROID_API__, but the standalone toolchain’s - # <android/api-level.h> will #define it for both Clang and GCC. - # - # android_api_level is extracted in this manner even when compiling with Clang - # so that it’s available for use in GYP conditions that need to test the API - # level, but beware that it’ll only be available when unified headers are in - # use. - # - # Unified headers are the way of the future, according to - # https://android.googlesource.com/platform/ndk/+/ndk-r14/CHANGELOG.md and - # https://android.googlesource.com/platform/ndk/+/master/docs/UnifiedHeaders.md. - # Traditional (deprecated) headers have been removed entirely as of NDK r16. - # https://android.googlesource.com/platform/ndk/+/ndk-release-r16/CHANGELOG.md. - with open(clang_path, 'r') as file: - clang_script_contents = file.read() - matches = re.finditer(r'\s-D__ANDROID_API__=([\d]+)\s', - clang_script_contents) - match = next(matches, None) - if match: - android_api = int(match.group(1)) - extra_args.extend(['-D', 'android_api_level=%d' % android_api]) - if next(matches, None): - raise AssertionError('__ANDROID_API__ defined too many times') + # ARM only includes 'v7a' in the tool prefix for clang + tool_prefix = ('arm-linux-androideabi' if parsed.arch == 'arm' + else ARCH_TO_ARCH_TRIPLET[parsed.arch]) for tool in ('ar', 'nm', 'readelf'): os.environ['%s_target' % tool.upper()] = ( - os.path.join(ndk_bin_dir, '%s-%s' % (arch_triplet, tool))) + os.path.join(ndk_bin_dir, '%s-%s' % (tool_prefix, tool))) return gyp_crashpad.main( ['-D', 'OS=android', - '-D', 'target_arch=%s' % arch, - '-D', 'clang=%d' % (1 if parsed.compiler == 'clang' else 0), + '-D', 'target_arch=%s' % parsed.arch, + '-D', 'clang=1', '-f', 'ninja-android'] + extra_args + extra_command_line_args) diff --git a/doc/developing.md b/doc/developing.md index f4a95e13..406a234f 100644 --- a/doc/developing.md +++ b/doc/developing.md @@ -135,66 +135,38 @@ target_sysroot = "//third_party/linux/sysroot" ### Android -Crashpad’s Android port is in its early stages. This build relies on -cross-compilation. It’s possible to develop Crashpad for Android on any platform -that the [Android NDK (Native Development -Kit)](https://developer.android.com/ndk/) runs on. +This build relies on cross-compilation. It’s possible to develop Crashpad for +Android on any platform that the [Android NDK (Native Development Kit)] +(https://developer.android.com/ndk/) runs on. If it’s not already present on your system, [download the NDK package for your system](https://developer.android.com/ndk/downloads/) and expand it to a suitable location. These instructions assume that it’s been expanded to -`~/android-ndk-r16`. - -To build Crashpad, portions of the NDK must be reassembled into a [standalone -toolchain](https://developer.android.com/ndk/guides/standalone_toolchain.html). -This is a repackaged subset of the NDK suitable for cross-compiling for a single -Android architecture (such as `arm`, `arm64`, `x86`, and `x86_64`) targeting a -specific [Android API -level](https://source.android.com/source/build-numbers.html). The standalone -toolchain only needs to be built from the NDK one time for each set of options -desired. To build a standalone toolchain targeting 64-bit ARM and API level 21 -(Android 5.0 “Lollipop”), run: - -``` -$ cd ~ -$ python android-ndk-r16/build/tools/make_standalone_toolchain.py \ - --arch=arm64 --api=21 --install-dir=android-ndk-r16_arm64_api21 -``` +`~/android-ndk-r20`. Note that Chrome uses Android API level 21 for 64-bit platforms and 16 for 32-bit platforms. See Chrome’s [`build/config/android/config.gni`](https://chromium.googlesource.com/chromium/src/+/master/build/config/android/config.gni) which sets `_android_api_level` and `_android64_api_level`. -To configure a Crashpad build for Android using the standalone toolchain -assembled above, use `gyp_crashpad_android.py`. This script is a wrapper for -`gyp_crashpad.py` that sets several environment variables directing the build to -the standalone toolchain, and several GYP options to identify an Android build. -This must be done after any `gclient sync`, or instead of any `gclient runhooks` -operation. +To configure a Crashpad build for Android use `gyp_crashpad_android.py`. This +script is a wrapper for `gyp_crashpad.py` that sets several environment +variables directing the build to the toolchain, and several GYP options to +identify an Android build. This must be done after any `gclient sync`, or +instead of any `gclient runhooks` operation. ``` $ cd ~/crashpad/crashpad -$ python build/gyp_crashpad_android.py \ - --ndk ~/android-ndk-r16_arm64_api21 \ - --generator-output out/android_arm64_api21 +python build/gyp_crashpad_android.py \ + --ndk ~/usr/lib/android-ndk-r20 --arch arm64 --api-level 21 \ + --generator-output=out/android_arm64_api21 \ ``` -`gyp_crashpad_android.py` detects the build type based on the characteristics of -the standalone toolchain given in its `--ndk` argument. - -`gyp_crashpad_android.py` sets the build up to use Clang by default. It’s also -possible to use GCC by providing the `--compiler=gcc` argument to -`gyp_crashpad_android.py`. - -The Android port is incomplete, but targets known to be working include -`crashpad_test`, `crashpad_util`, and their tests. This list will grow over -time. To build, direct `ninja` to the specific `out` directory chosen by the +To build, direct `ninja` to the specific `out` directory chosen by the `--generator-output` argument to `gyp_crashpad_android.py`. ``` -$ ninja -C out/android_arm64_api21/out/Debug \ - crashpad_test_test crashpad_util_test +$ ninja -C out/android_arm64_api21/out/Debug all ``` ## Testing diff --git a/handler/handler.gyp b/handler/handler.gyp index 60a6f251..f80b5f02 100644 --- a/handler/handler.gyp +++ b/handler/handler.gyp @@ -39,6 +39,8 @@ 'crash_report_upload_thread.h', 'handler_main.cc', 'handler_main.h', + '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', diff --git a/util/util.gyp b/util/util.gyp index c7d735fb..b9da2324 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -395,8 +395,8 @@ ['OS=="linux" or OS=="android"', { 'sources': [ 'net/http_transport_socket.cc', - 'util/process_memory_sanitized.cc', - 'util/process_memory_sanitized.h', + 'process/process_memory_sanitized.cc', + 'process/process_memory_sanitized.h', ], }, { # else: OS!="linux" 'sources!': [ diff --git a/util/util_test.gyp b/util/util_test.gyp index c819e6db..f65a9186 100644 --- a/util/util_test.gyp +++ b/util/util_test.gyp @@ -156,7 +156,7 @@ }], ['OS=="linux" or OS=="android"', { 'sources': [ - 'util/process_memory_sanitized_test.cc', + 'process/process_memory_sanitized_test.cc', ], }], ['OS!="linux" and OS!="android"', { From 2bfd3c4edcff500f3cf07957518d1311b0a5b2c1 Mon Sep 17 00:00:00 2001 From: Alex Pankhurst <pankhurst@google.com> Date: Tue, 10 Sep 2019 10:16:01 -0700 Subject: [PATCH 263/401] [POSIX] stop logging on ENOENT This change stops IsRegularFile and IsDirectory from logging an error in the instance that a file or directory cannot be found. Change-Id: I9f3c409933245708db775f566a27f5e49b2c71f3 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1795924 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- util/file/filesystem.h | 6 +++++- util/file/filesystem_posix.cc | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/util/file/filesystem.h b/util/file/filesystem.h index 27a4d1de..e12f1271 100644 --- a/util/file/filesystem.h +++ b/util/file/filesystem.h @@ -73,7 +73,8 @@ bool MoveFileOrDirectory(const base::FilePath& source, //! failure. //! //! On POSIX, this function returns `true` if \a path refers to a file that is -//! not a symbolic link, directory, or other kind of special file. +//! not a symbolic link, directory, or other kind of special file. If this +//! function fails because \a path does not exist, then no message is logged. //! //! On Windows, this function returns `true` if \a path refers to a file that //! is not a symbolic link or directory. @@ -85,6 +86,9 @@ bool IsRegularFile(const base::FilePath& path); //! \brief Determines if a path refers to a directory, logging a message on //! failure. //! +//! On POSIX, if this function fails because \a path does not exist, then no +//! message is logged. +//! //! \param[in] path The path to check. //! \param[in] allow_symlinks Whether to allow the final component in the path //! to be a symbolic link to a directory. diff --git a/util/file/filesystem_posix.cc b/util/file/filesystem_posix.cc index b1f19f62..bb51a9c1 100644 --- a/util/file/filesystem_posix.cc +++ b/util/file/filesystem_posix.cc @@ -76,7 +76,7 @@ bool MoveFileOrDirectory(const base::FilePath& source, bool IsRegularFile(const base::FilePath& path) { struct stat st; if (lstat(path.value().c_str(), &st) != 0) { - PLOG(ERROR) << "stat " << path.value(); + PLOG_IF(ERROR, errno != ENOENT) << "stat " << path.value(); return false; } return S_ISREG(st.st_mode); @@ -86,11 +86,11 @@ bool IsDirectory(const base::FilePath& path, bool allow_symlinks) { struct stat st; if (allow_symlinks) { if (stat(path.value().c_str(), &st) != 0) { - PLOG(ERROR) << "stat " << path.value(); + PLOG_IF(ERROR, errno != ENOENT) << "stat " << path.value(); return false; } } else if (lstat(path.value().c_str(), &st) != 0) { - PLOG(ERROR) << "lstat " << path.value(); + PLOG_IF(ERROR, errno != ENOENT) << "lstat " << path.value(); return false; } return S_ISDIR(st.st_mode); From 12bc30cdf58a532771f3fba77b0eb10ce8ca9886 Mon Sep 17 00:00:00 2001 From: Alex Pankhurst <pankhurst@google.com> Date: Tue, 10 Sep 2019 13:40:27 -0700 Subject: [PATCH 264/401] Check if attachment directories exist before open TESTED=`fx run-test crashpad_test -- --gtest_filter=Filesystem.Is*` Change-Id: If5940e56fbfd890e73d4403b530bc3e4a32e0365 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1796965 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- client/crash_report_database_generic.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/crash_report_database_generic.cc b/client/crash_report_database_generic.cc index bbdb2444..aeaf2af4 100644 --- a/client/crash_report_database_generic.cc +++ b/client/crash_report_database_generic.cc @@ -173,8 +173,7 @@ off_t GetFileSize(const base::FilePath& filepath) { void AddAttachmentSize(const base::FilePath& attachments_dir, uint64_t* size) { // Early return if the attachment directory does not exist. - struct stat statbuf; - if (stat(attachments_dir.value().c_str(), &statbuf) != 0) { + if (!IsDirectory(attachments_dir, /*allow_symlinks=*/false)) { return; } DirectoryReader reader; @@ -334,6 +333,9 @@ void CrashReportDatabase::UploadReport::InitializeAttachments() { base::FilePath attachments_dir = static_cast<CrashReportDatabaseGeneric*>(database_)->AttachmentsPath( uuid); + if (!IsDirectory(attachments_dir, /*allow_symlinks=*/false)) { + return; + } DirectoryReader reader; if (!reader.Open(attachments_dir)) { return; @@ -873,7 +875,6 @@ void CrashReportDatabaseGeneric::CleanOrphanedAttachments() { base::FilePath root_attachments_dir(base_dir_.Append(kAttachmentsDirectory)); DirectoryReader reader; if (!reader.Open(root_attachments_dir)) { - LOG(ERROR) << "no attachments dir"; return; } @@ -914,6 +915,9 @@ void CrashReportDatabaseGeneric::CleanOrphanedAttachments() { void CrashReportDatabaseGeneric::RemoveAttachmentsByUUID(const UUID& uuid) { base::FilePath attachments_dir = AttachmentsPath(uuid); + if (!IsDirectory(attachments_dir, /*allow_symlinks=*/false)) { + return; + } DirectoryReader reader; if (!reader.Open(attachments_dir)) { return; From edbbc4609d2d0703ed73ba9293971f1346234313 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 17 Sep 2019 12:10:45 -0700 Subject: [PATCH 265/401] chromeos: fix typo Change-Id: I14f84e718b55730e83b01e580d59eacdf6fc7f5d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1809644 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- handler/handler_main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handler/handler_main.cc b/handler/handler_main.cc index d5a9e609..9fce9fc1 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -644,7 +644,7 @@ int HandlerMain(int argc, kOptionTraceParentWithException}, #endif // OS_LINUX || OS_ANDROID {"url", required_argument, nullptr, kOptionURL}, -#if defined(OS_CHROEMOS) +#if defined(OS_CHROMEOS) {"use-cros-crash-reporter", no_argument, nullptr, From c405d0ea2cbd76a30d001ceae3823cb41af650fb Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Mon, 16 Sep 2019 15:54:13 -0700 Subject: [PATCH 266/401] make PruneCrashReportDatabase return the number of pruned crash reports Change-Id: I270ea8df5054ede9731c7a0a22439a1409eee6d9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1808138 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- client/prune_crash_reports.cc | 12 +++++++++--- client/prune_crash_reports.h | 6 ++++-- client/prune_crash_reports_test.cc | 10 ++++++---- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/client/prune_crash_reports.cc b/client/prune_crash_reports.cc index c6fa389b..8eed18d4 100644 --- a/client/prune_crash_reports.cc +++ b/client/prune_crash_reports.cc @@ -15,6 +15,7 @@ #include "client/prune_crash_reports.h" #include <sys/stat.h> +#include <stdint.h> #include <algorithm> #include <vector> @@ -24,7 +25,7 @@ namespace crashpad { -void PruneCrashReportDatabase(CrashReportDatabase* database, +size_t PruneCrashReportDatabase(CrashReportDatabase* database, PruneCondition* condition) { std::vector<CrashReportDatabase::Report> all_reports; CrashReportDatabase::OperationStatus status; @@ -32,14 +33,14 @@ void PruneCrashReportDatabase(CrashReportDatabase* database, status = database->GetPendingReports(&all_reports); if (status != CrashReportDatabase::kNoError) { LOG(ERROR) << "PruneCrashReportDatabase: Failed to get pending reports"; - return; + return 0; } std::vector<CrashReportDatabase::Report> completed_reports; status = database->GetCompletedReports(&completed_reports); if (status != CrashReportDatabase::kNoError) { LOG(ERROR) << "PruneCrashReportDatabase: Failed to get completed reports"; - return; + return 0; } all_reports.insert(all_reports.end(), completed_reports.begin(), completed_reports.end()); @@ -50,16 +51,21 @@ void PruneCrashReportDatabase(CrashReportDatabase* database, return lhs.creation_time > rhs.creation_time; }); + size_t num_pruned = 0; for (const auto& report : all_reports) { if (condition->ShouldPruneReport(report)) { status = database->DeleteReport(report.uuid); if (status != CrashReportDatabase::kNoError) { LOG(ERROR) << "Database Pruning: Failed to remove report " << report.uuid.ToString(); + } else { + num_pruned++; } } } + return num_pruned; + // TODO(rsesek): For databases that do not use a directory structure, it is // possible for the metadata sidecar to become corrupted and thus leave // orphaned crash report files on-disk. https://crashpad.chromium.org/bug/66 diff --git a/client/prune_crash_reports.h b/client/prune_crash_reports.h index 6dac5f30..07a70980 100644 --- a/client/prune_crash_reports.h +++ b/client/prune_crash_reports.h @@ -37,8 +37,10 @@ class PruneCondition; //! \param[in] database The database from which crash reports will be deleted. //! \param[in] condition The condition against which all reports in the database //! will be evaluated. -void PruneCrashReportDatabase(CrashReportDatabase* database, - PruneCondition* condition); +//! +//! \return The number of deleted crash reports. +size_t PruneCrashReportDatabase(CrashReportDatabase* database, + PruneCondition* condition); std::unique_ptr<PruneCondition> GetDefaultDatabasePruneCondition(); diff --git a/client/prune_crash_reports_test.cc b/client/prune_crash_reports_test.cc index c8c43444..dbe8c0a5 100644 --- a/client/prune_crash_reports_test.cc +++ b/client/prune_crash_reports_test.cc @@ -15,6 +15,7 @@ #include "client/prune_crash_reports.h" #include <stddef.h> +#include <stdint.h> #include <stdlib.h> #include <algorithm> @@ -204,11 +205,12 @@ TEST(PruneCrashReports, PruneOrder) { using ::testing::Return; using ::testing::SetArgPointee; + const size_t kNumReports = 10; std::vector<CrashReportDatabase::Report> reports; - for (int i = 0; i < 10; ++i) { + for (size_t i = 0; i < kNumReports; ++i) { CrashReportDatabase::Report temp; - temp.uuid.data_1 = i; - temp.creation_time = NDaysAgo(i * 10); + temp.uuid.data_1 = static_cast<uint32_t>(i); + temp.creation_time = NDaysAgo(static_cast<int>(i) * 10); reports.push_back(temp); } std::mt19937 urng(std::random_device{}()); @@ -231,7 +233,7 @@ TEST(PruneCrashReports, PruneOrder) { } StaticCondition delete_all(true); - PruneCrashReportDatabase(&db, &delete_all); + EXPECT_EQ(PruneCrashReportDatabase(&db, &delete_all), kNumReports); } } // namespace From eff0680c139338170d0821ad19d7ab1ad2e8811b Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 20 Sep 2019 11:19:38 -0700 Subject: [PATCH 267/401] linux: silence logs on client disconnect When all Crashpad clients have closed their crash handling sockets, the handler's recvmsg() returns 0 and doesn't include any credentials. Silence error logs for this normally occurring case. Change-Id: I56acf3b38c8e95a9bbaa9bff04e0a6859a194e66 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1816286 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/linux/socket.cc | 12 ++++++------ util/linux/socket.h | 6 +++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/util/linux/socket.cc b/util/linux/socket.cc index 68efd570..f56eacf6 100644 --- a/util/linux/socket.cc +++ b/util/linux/socket.cc @@ -168,17 +168,17 @@ bool UnixCredentialSocket::RecvMsg(int fd, return false; } + // Credentials are missing from the message either when the recv socket wasn't + // configured with SO_PASSCRED or when all sending sockets have been closed. + // In the latter case, res == 0. This case is also indistinguishable from an + // empty message sent to a recv socket which hasn't set SO_PASSCRED. if (!local_creds) { - LOG(ERROR) << "missing credentials"; + LOG_IF(ERROR, res != 0) << "missing credentials"; return false; } - // res == 0 may also indicate that the sending socket disconnected, but in - // that case, the message will also have missing or invalid credentials. if (static_cast<size_t>(res) != buf_size) { - if (res != 0 || (local_creds && local_creds->pid != 0)) { - LOG(ERROR) << "incorrect payload size " << res; - } + LOG(ERROR) << "incorrect payload size " << res; return false; } diff --git a/util/linux/socket.h b/util/linux/socket.h index c02a6c30..85860f7b 100644 --- a/util/linux/socket.h +++ b/util/linux/socket.h @@ -76,7 +76,11 @@ class UnixCredentialSocket { //! \param[out] creds The credentials of the sender. //! \param[out] fds The recieved file descriptors. Optional. If `nullptr`, all //! received file descriptors will be closed. - //! \return `true` on success. Otherwise, `false`, with a message logged. + //! \return `true` on success. Otherwise, `false`, with a message logged. No + //! message will be logged if the message was detected to be an EOF + //! condition triggered by all clients disconnecting. This case is + //! indistinguishable from misuses of this interface that haven't set + //! `SO_PASSCRED` on \a fd. static bool RecvMsg(int fd, void* buf, size_t buf_size, From 676a190308b1492bdb6c1f8889247d4dfedefaf1 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 30 Sep 2019 13:56:12 -0700 Subject: [PATCH 268/401] linux: fix --monitor-self The metrics recording signal handler doesn't need to be re-installed on Linux because the handler installed by StartHandler() restores the previously installed handler by default. Reinstalling the metrics handler results in a crash dump loop in which each signal handler restores the other. Change-Id: Ieef40c74bfc69f6e0caef9809f33cfcaa10f0d03 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1832153 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client_linux.cc | 1 - handler/handler_main.cc | 29 ++++++----------------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index c3ebbd4c..f1368ec7 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -352,7 +352,6 @@ bool CrashpadClient::StartHandler( const std::vector<std::string>& arguments, bool restartable, bool asynchronous_start) { - DCHECK(!restartable); DCHECK(!asynchronous_start); ScopedFileHandle client_sock, handler_sock; diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 9fce9fc1..7d9701c0 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -263,8 +263,6 @@ class CallMetricsRecordNormalExit { #if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_ANDROID) -Signals::OldActions g_old_crash_signal_handlers; - void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed); @@ -299,9 +297,7 @@ void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { } Metrics::HandlerCrashed(metrics_code); - struct sigaction* old_action = - g_old_crash_signal_handlers.ActionForSignal(sig); - Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, old_action); + Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr); } void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) { @@ -309,13 +305,13 @@ void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) { Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr); } -#if defined(OS_MACOSX) - void ReinstallCrashHandler() { // This is used to re-enable the metrics-recording crash handler after // MonitorSelf() sets up a Crashpad exception handler. On macOS, the // metrics-recording handler uses signals and the Crashpad handler uses Mach // exceptions, so there’s nothing to re-enable. + // On Linux, the signal handler installed by StartHandler() restores the + // previously installed signal handler by default. } void InstallCrashHandler() { @@ -325,6 +321,8 @@ void InstallCrashHandler() { Signals::InstallTerminateHandlers(HandleTerminateSignal, 0, nullptr); } +#if defined(OS_MACOSX) + struct ResetSIGTERMTraits { static struct sigaction* InvalidValue() { return nullptr; @@ -349,21 +347,6 @@ void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { g_exception_handler_server->Stop(); } -#else - -void ReinstallCrashHandler() { - // This is used to re-enable the metrics-recording crash handler after - // MonitorSelf() sets up a Crashpad signal handler. - Signals::InstallCrashHandlers( - HandleCrashSignal, 0, &g_old_crash_signal_handlers); -} - -void InstallCrashHandler() { - ReinstallCrashHandler(); - - Signals::InstallTerminateHandlers(HandleTerminateSignal, 0, nullptr); -} - #endif // OS_MACOSX #elif defined(OS_WIN) @@ -473,7 +456,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_LINUX) || defined(OS_ANDROID) +#if defined(OS_ANDROID) if (!crashpad_client.StartHandlerAtCrash(executable_path, options.database, base::FilePath(), From eb0c4726f13d06662b0cf82571e5047b386d6dae Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 3 Oct 2019 10:25:00 -0700 Subject: [PATCH 269/401] linux: make GetHandlerSocket() params optional It turns out it's frequently convenient to only grab one of these at a time. Change-Id: Ie4a05583a5c875163154efc485d57a014101cc16 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1838011 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client.h | 4 ++-- client/crashpad_client_linux.cc | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index dfe13538..207f9784 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -124,8 +124,8 @@ class CrashpadClient { //! `StartHandler()` must have successfully been called before calling this //! method. //! - //! \param[out] sock The socket connected to the handler. - //! \param[out] pid The handler's process ID. + //! \param[out] sock The socket connected to the handler, if not `nullptr`. + //! \param[out] pid The handler's process ID, if not `nullptr`. //! \return `true` on success. Otherwise `false` with a message logged. static bool GetHandlerSocket(int* sock, pid_t* pid); diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index f1368ec7..74f15403 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -295,8 +295,12 @@ class RequestCrashDumpHandler : public SignalHandler { if (!sock_to_handler_.is_valid()) { return false; } - *sock = sock_to_handler_.get(); - *pid = handler_pid_; + if (sock) { + *sock = sock_to_handler_.get(); + } + if (pid) { + *pid = handler_pid_; + } return true; } From c87486f5951f0b6445730d03e388b1f6f68ef7b8 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 4 Oct 2019 12:13:16 -0700 Subject: [PATCH 270/401] android: insert app_process at start of handler argv HandlerMain() consumes argv[0] as the name for itself. Arguments before the class name are consumed by app_process when using a Java handler. Re-insert app_process for HandlerMain() to consume as the program name or else it will consume the next real argument. Bug: chromium:1011145 Change-Id: Id7090db36cc382a9fdba49b9259dbbce3a9bcc5c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1841974 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_linux.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 74f15403..00a83fa0 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -58,24 +58,31 @@ std::vector<std::string> BuildAppProcessArgs( const std::map<std::string, std::string>& annotations, const std::vector<std::string>& arguments, int socket) { - std::vector<std::string> argv; #if defined(ARCH_CPU_64_BITS) - argv.push_back("/system/bin/app_process64"); + static constexpr char kAppProcess[] = "/system/bin/app_process64"; #else - argv.push_back("/system/bin/app_process32"); + static constexpr char kAppProcess[] = "/system/bin/app_process32"; #endif + + std::vector<std::string> argv; + argv.push_back(kAppProcess); argv.push_back("/system/bin"); argv.push_back("--application"); argv.push_back(class_name); - std::vector<std::string> handler_argv = BuildHandlerArgvStrings( - base::FilePath(), database, metrics_dir, url, annotations, arguments); + std::vector<std::string> handler_argv = + BuildHandlerArgvStrings(base::FilePath(kAppProcess), + database, + metrics_dir, + url, + annotations, + arguments); if (socket != kInvalidFileHandle) { handler_argv.push_back(FormatArgumentInt("initial-client-fd", socket)); } - argv.insert(argv.end(), handler_argv.begin() + 1, handler_argv.end()); + argv.insert(argv.end(), handler_argv.begin(), handler_argv.end()); return argv; } From fe52a01df1e9c8a5fe8b92872d4bf8689d0cd3b4 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 9 Oct 2019 11:00:00 -0700 Subject: [PATCH 271/401] linux: set dumpable for all signal handlers Change-Id: I6e3d6627332d7dd9eb029b9778f72d7af1511153 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1850234 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client_linux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 00a83fa0..01883243 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -155,6 +155,7 @@ class SignalHandler { context); exception_information_.thread_id = sys_gettid(); + ScopedPrSetDumpable set_dumpable(false); HandleCrashImpl(); return false; } @@ -228,7 +229,6 @@ class LaunchAtCrashHandler : public SignalHandler { void HandleCrashImpl() override { ScopedPrSetPtracer set_ptracer(sys_getpid(), /* may_log= */ false); - ScopedPrSetDumpable set_dumpable(/* may_log= */ false); pid_t pid = fork(); if (pid < 0) { From 2fb4e9e6a4328ed49b15eec0a848fcc646208840 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Thu, 10 Oct 2019 17:34:12 -0400 Subject: [PATCH 272/401] mac: Update the process_types version of dyld_all_image_infos for 10.15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS 10.15 (“Catalina”) introduces a single new field to its dyld_all_image_infos structure, and uses structure version 16. macOS 10.13 and 10.14 were documented in <mach-o/dyld_images.h> as using structure version 16, but they actually use version 15. They should have used version 16, as they do use a structure expanded from macOS 10.12, which also uses version 15. Previously, process_types was true to the documentation, but now that this is known to be incorrect, it’s been revised to reflect reality. Because two variants of the version 15 structure exist, run-time OS version detection is used to disambiguate. Bug: crashpad:310 Test: crashpad_snapshot_test ProcessTypes.DyldImagesSelf (10.15 SDK) Change-Id: Ibc82b6a73809949f4bbf416ece7aa955b627c573 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1852109 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Robert Sesek <rsesek@chromium.org> --- compat/mac/AvailabilityMacros.h | 12 +++ snapshot/mac/process_types/custom.cc | 28 ++++++- .../mac/process_types/dyld_images.proctype | 20 +++-- snapshot/mac/process_types_test.cc | 79 ++++++++++++++++--- 4 files changed, 116 insertions(+), 23 deletions(-) diff --git a/compat/mac/AvailabilityMacros.h b/compat/mac/AvailabilityMacros.h index f105f944..a83d2a42 100644 --- a/compat/mac/AvailabilityMacros.h +++ b/compat/mac/AvailabilityMacros.h @@ -59,4 +59,16 @@ #define MAC_OS_X_VERSION_10_13 101300 #endif +// 10.14 SDK + +#ifndef MAC_OS_X_VERSION_10_14 +#define MAC_OS_X_VERSION_10_14 101400 +#endif + +// 10.15 SDK + +#ifndef MAC_OS_X_VERSION_10_15 +#define MAC_OS_X_VERSION_10_15 101500 +#endif + #endif // CRASHPAD_COMPAT_MAC_AVAILABILITYMACROS_H_ diff --git a/snapshot/mac/process_types/custom.cc b/snapshot/mac/process_types/custom.cc index 3ca5646c..a76c3ebb 100644 --- a/snapshot/mac/process_types/custom.cc +++ b/snapshot/mac/process_types/custom.cc @@ -19,6 +19,7 @@ #include <sys/types.h> #include <algorithm> +#include <limits> #include <type_traits> #include "base/logging.h" @@ -26,6 +27,7 @@ #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "snapshot/mac/process_types/internal.h" +#include "util/mac/mac_util.h" #include "util/process/process_memory_mac.h" #if !DOXYGEN @@ -140,8 +142,8 @@ size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion( offsetof(dyld_all_image_infos<Traits>, sharedCacheSlide), // 11 offsetof(dyld_all_image_infos<Traits>, sharedCacheUUID), // 12 offsetof(dyld_all_image_infos<Traits>, infoArrayChangeTimestamp), // 13 - offsetof(dyld_all_image_infos<Traits>, end_14_15), // 14 - offsetof(dyld_all_image_infos<Traits>, end_14_15), // 15 + offsetof(dyld_all_image_infos<Traits>, end_14), // 14 + std::numeric_limits<size_t>::max(), // 15, see below sizeof(dyld_all_image_infos<Traits>), // 16 }; @@ -151,7 +153,27 @@ size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion( static_assert(std::is_unsigned<decltype(version)>::value, "version must be unsigned"); - return kSizeForVersion[version]; + + if (version == 15) { + // Disambiguate between the two different layouts for version 15. The + // original one introduced in macOS 10.12 had the same size as version 14. + // The revised one in macOS 10.13 grew. It’s safe to assume that the + // dyld_all_image_infos structure came from the same system that’s now + // interpreting it, so use an OS version check. + int mac_os_x_minor_version = MacOSXMinorVersion(); + if (mac_os_x_minor_version == 12) { + return offsetof(dyld_all_image_infos<Traits>, end_14); + } + + DCHECK_GE(mac_os_x_minor_version, 13); + DCHECK_LE(mac_os_x_minor_version, 14); + return offsetof(dyld_all_image_infos<Traits>, platform); + } + + size_t size = kSizeForVersion[version]; + DCHECK_NE(size, std::numeric_limits<size_t>::max()); + + return size; } // static diff --git a/snapshot/mac/process_types/dyld_images.proctype b/snapshot/mac/process_types/dyld_images.proctype index f92a8009..3b040854 100644 --- a/snapshot/mac/process_types/dyld_images.proctype +++ b/snapshot/mac/process_types/dyld_images.proctype @@ -121,23 +121,29 @@ PROCESS_TYPE_STRUCT_BEGIN(dyld_all_image_infos) // the runtimes that use versions 14 and 15 were built with SDKs that did not // have this extra padding, it’s necessary to treat the element at index 4 on // 32-bit systems as outside of the version 14 and 15 structure. This is why - // |reserved| is only declared a 4-element array, with a special end_14_15 - // member (not present in the native definition) available to indicate the - // end of the native version 14 and 15 structure, preceding the padding in the - // 32-bit structure that would natively be addressed at index 4 of |reserved|. - // Treat reserved_4_32 as only available in version 16 of the structure. + // |reserved| is only declared a 4-element array, with a special end_14 member + // (not present in the native definition) available to indicate the end of the + // native version 14 structure and the 10.12 version 15 structure, preceding + // the padding in the 32-bit structure that would natively be addressed at + // index 4 of |reserved|. Treat reserved_4_32 as only available in version 16 + // of the structure. PROCESS_TYPE_STRUCT_MEMBER(UIntPtr, reserved, [4]) PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_4_64) PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_5) PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_6) PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_7) PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_8) - PROCESS_TYPE_STRUCT_MEMBER(Nothing, end_14_15) + PROCESS_TYPE_STRUCT_MEMBER(Nothing, end_14) PROCESS_TYPE_STRUCT_MEMBER(Reserved32_32Only, reserved_4_32) - // Version 16 (macOS 10.13) + // Version 15 (macOS 10.13). <mach-o/dyld_images.h> incorrectly claims that + // these were introduced at version 16. These fields are not present in macOS + // 10.12, which also identifies its structure as version 15. PROCESS_TYPE_STRUCT_MEMBER(UIntPtr, compact_dyld_image_info_addr) PROCESS_TYPE_STRUCT_MEMBER(ULong, compact_dyld_image_info_size) // size_t + + // Version 16 (macOS 10.15) + PROCESS_TYPE_STRUCT_MEMBER(uint32_t, platform) // dyld_platform_t PROCESS_TYPE_STRUCT_END(dyld_all_image_infos) #endif // ! PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO && diff --git a/snapshot/mac/process_types_test.cc b/snapshot/mac/process_types_test.cc index 2ab3034c..8523b9cb 100644 --- a/snapshot/mac/process_types_test.cc +++ b/snapshot/mac/process_types_test.cc @@ -18,6 +18,7 @@ #include <mach/mach.h> #include <string.h> +#include <limits> #include <vector> #include "base/stl_util.h" @@ -47,13 +48,11 @@ namespace { TEST(ProcessTypes, DyldImagesSelf) { // Get the in-process view of dyld_all_image_infos, and check it for sanity. const dyld_all_image_infos* self_image_infos = DyldGetAllImageInfos(); - int mac_os_x_minor_version = MacOSXMinorVersion(); + const int mac_os_x_minor_version = MacOSXMinorVersion(); - // The 10.13 SDK defines dyld_all_image_infos version 16 and says that it’s - // used on 10.13, but 10.13db1 17A264c uses version 15. - // - // TODO(mark): Recheck later in the beta period, up to the 10.13 release. - if (mac_os_x_minor_version >= 12) { + if (mac_os_x_minor_version >= 15) { + EXPECT_GE(self_image_infos->version, 16u); + } else if (mac_os_x_minor_version >= 12) { EXPECT_GE(self_image_infos->version, 15u); } else if (mac_os_x_minor_version >= 9) { EXPECT_GE(self_image_infos->version, 13u); @@ -104,7 +103,7 @@ TEST(ProcessTypes, DyldImagesSelf) { ProcessReaderMac process_reader; ASSERT_TRUE(process_reader.Initialize(mach_task_self())); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15 constexpr uint32_t kDyldAllImageInfosVersionInSDK = 16; #elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12 constexpr uint32_t kDyldAllImageInfosVersionInSDK = 15; @@ -120,12 +119,33 @@ TEST(ProcessTypes, DyldImagesSelf) { // Make sure that the size of the structure as declared in the SDK matches the // size expected for the version of the structure that the SDK describes. - EXPECT_EQ(process_types::dyld_all_image_infos::ExpectedSizeForVersion( - &process_reader, kDyldAllImageInfosVersionInSDK), - sizeof(dyld_all_image_infos)); + // + // There are two possible layouts for version 15, and the + // ExpectedSizeForVersion() implementation infers the correct one based on the + // run-time OS version, so if the SDK defines the version 15 structure, this + // test can only be performed if the run-time OS natively uses the same format + // structure as the SDK. + bool test_expected_size_for_version_matches_sdk_sizeof; +#if MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_12 + test_expected_size_for_version_matches_sdk_sizeof = + mac_os_x_minor_version == 12; +#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 && \ + MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_14 + test_expected_size_for_version_matches_sdk_sizeof = + mac_os_x_minor_version >= 13 && mac_os_x_minor_version <= 14; +#else + test_expected_size_for_version_matches_sdk_sizeof = true; +#endif + + if (test_expected_size_for_version_matches_sdk_sizeof) { + EXPECT_EQ(process_types::dyld_all_image_infos::ExpectedSizeForVersion( + &process_reader, kDyldAllImageInfosVersionInSDK), + sizeof(dyld_all_image_infos)); + } // Make sure that the computed sizes of various versions of this structure are // correct at different bitnessses. + constexpr size_t kSpecialCase = std::numeric_limits<size_t>::max(); constexpr struct { uint32_t version; size_t size_32; @@ -144,13 +164,40 @@ TEST(ProcessTypes, DyldImagesSelf) { {12, 84, 160}, {13, 104, 184}, {14, 164, 304}, - {15, 164, 304}, - {16, 176, 320}, + {15, kSpecialCase, kSpecialCase}, + {16, 184, 328}, }; for (size_t index = 0; index < base::size(kVersionsAndSizes); ++index) { uint32_t version = kVersionsAndSizes[index].version; SCOPED_TRACE(base::StringPrintf("index %zu, version %u", index, version)); + if (version == 15) { + if (mac_os_x_minor_version == 12) { + EXPECT_EQ(process_types::internal::dyld_all_image_infos< + process_types::internal::Traits32>:: + ExpectedSizeForVersion(version), + 164u); + EXPECT_EQ(process_types::internal::dyld_all_image_infos< + process_types::internal::Traits64>:: + ExpectedSizeForVersion(version), + 304u); + } else if (mac_os_x_minor_version >= 13 && mac_os_x_minor_version <= 14) { + EXPECT_EQ(process_types::internal::dyld_all_image_infos< + process_types::internal::Traits32>:: + ExpectedSizeForVersion(version), + 176u); + EXPECT_EQ(process_types::internal::dyld_all_image_infos< + process_types::internal::Traits64>:: + ExpectedSizeForVersion(version), + 320u); + } + + continue; + } + + ASSERT_NE(kVersionsAndSizes[index].size_32, kSpecialCase); + ASSERT_NE(kVersionsAndSizes[index].size_64, kSpecialCase); + EXPECT_EQ( process_types::internal::dyld_all_image_infos< process_types::internal::Traits32>::ExpectedSizeForVersion(version), @@ -306,7 +353,7 @@ TEST(ProcessTypes, DyldImagesSelf) { #endif #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 - if (proctype_image_infos.version >= 16) { + if (proctype_image_infos.version >= 15 && mac_os_x_minor_version >= 13) { EXPECT_EQ(proctype_image_infos.compact_dyld_image_info_addr, self_image_infos->compact_dyld_image_info_addr); EXPECT_EQ(proctype_image_infos.compact_dyld_image_info_size, @@ -314,6 +361,12 @@ TEST(ProcessTypes, DyldImagesSelf) { } #endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15 + if (proctype_image_infos.version >= 16) { + EXPECT_EQ(proctype_image_infos.platform, self_image_infos->platform); + } +#endif + if (proctype_image_infos.version >= 1) { std::vector<process_types::dyld_image_info> proctype_image_info_vector( proctype_image_infos.infoArrayCount); From c009b85449cba9c0037a8b8c561b638760b4c789 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 11 Oct 2019 12:07:21 -0400 Subject: [PATCH 273/401] Use GTEST_SKIP() instead of custom DISABLED_TEST() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since gtest 00938b2b228f, gtest has built-in first-class support for skipping tests, which is functionally identical (at least in Crashpad’s usage) to the home-grown support for run-time dynamically disabled tests introduced in Crashpad 5e9ed4cb9f69. Use the new standard pattern, and remove all vestiges of the custom local one. This was done previously in 79f4a3970a64, but was reverted in bba9d0819c12 because Chromium’s test launcher did not support GTEST_SKIP() at the time. The deficiency is on file as https://crbug.com/912138. While that bug was never specifically marked as “fixed” and I haven’t found what changed in Chromium, I do now see some use of GTEST_SKIP() in Chromium. I also prototyped this change in Chromium at https://chromium-review.googlesource.com/c/1854691/ and found that GTEST_SKIP() does indeed now appear to work. Change-Id: I13fef8fe8bfd9854a40dfa5910a3282d1a85bc45 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1855380 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- client/crash_report_database_test.cc | 5 +- snapshot/linux/process_reader_linux_test.cc | 3 +- snapshot/win/exception_snapshot_win_test.cc | 5 +- snapshot/win/extra_memory_ranges_test.cc | 5 +- snapshot/win/module_snapshot_win_test.cc | 5 +- snapshot/win/process_snapshot_win_test.cc | 3 +- test/BUILD.gn | 2 - test/gtest_disabled.cc | 83 -------------------- test/gtest_disabled.h | 87 --------------------- test/gtest_main.cc | 3 - test/test.gyp | 2 - util/file/directory_reader_test.cc | 5 +- util/file/filesystem_test.cc | 13 ++- util/win/process_info_test.cc | 3 +- 14 files changed, 19 insertions(+), 205 deletions(-) delete mode 100644 test/gtest_disabled.cc delete mode 100644 test/gtest_disabled.h diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index ca66bce6..ef217c19 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,7 +670,7 @@ 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(); + GTEST_SKIP(); #else std::unique_ptr<CrashReportDatabase::NewReport> new_report; ASSERT_EQ(db()->PrepareNewCrashReport(&new_report), @@ -717,7 +716,7 @@ TEST_F(CrashReportDatabaseTest, Attachments) { TEST_F(CrashReportDatabaseTest, OrphanedAttachments) { #if defined(OS_MACOSX) || defined(OS_WIN) // Attachments aren't supported on Mac and Windows yet. - DISABLED_TEST(); + 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. diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index d7677002..a69a4c02 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -38,7 +38,6 @@ #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" -#include "test/gtest_disabled.h" #include "test/linux/fake_ptrace_connection.h" #include "test/linux/get_tls.h" #include "test/multiprocess.h" @@ -809,7 +808,7 @@ TEST(ProcessReaderLinux, AbortMessage) { // presence of a libc symbol which was introduced in Q. if (!crashpad::internal::Dlsym(RTLD_DEFAULT, "android_fdsan_close_with_tag")) { - DISABLED_TEST(); + GTEST_SKIP(); } android_set_abort_message(kTestAbortMessage); diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index 486e6df3..b4c44a83 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -23,7 +23,6 @@ #include "gtest/gtest.h" #include "snapshot/win/process_snapshot_win.h" #include "test/errors.h" -#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -176,7 +175,7 @@ TEST(ExceptionSnapshotWinTest, MAYBE_ChildCrash) { #if defined(ARCH_CPU_64_BITS) TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestCrashingChild(TestPaths::Architecture::k32Bit); @@ -293,7 +292,7 @@ TEST(SimulateCrash, MAYBE_ChildDumpWithoutCrashing) { #if defined(ARCH_CPU_64_BITS) TEST(SimulateCrash, ChildDumpWithoutCrashingWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestDumpWithoutCrashingChild(TestPaths::Architecture::k32Bit); diff --git a/snapshot/win/extra_memory_ranges_test.cc b/snapshot/win/extra_memory_ranges_test.cc index dcef8055..e0c17a20 100644 --- a/snapshot/win/extra_memory_ranges_test.cc +++ b/snapshot/win/extra_memory_ranges_test.cc @@ -25,7 +25,6 @@ #include "client/simple_address_range_bag.h" #include "gtest/gtest.h" #include "snapshot/win/process_snapshot_win.h" -#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -110,7 +109,7 @@ TEST(ExtraMemoryRanges, CrashDebugBreak) { #if defined(ARCH_CPU_64_BITS) TEST(ExtraMemoryRanges, DontCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestExtraMemoryRanges(kDontCrash, TestPaths::Architecture::k32Bit); @@ -118,7 +117,7 @@ TEST(ExtraMemoryRanges, DontCrashWOW64) { TEST(ExtraMemoryRanges, CrashDebugBreakWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Architecture::k32Bit); diff --git a/snapshot/win/module_snapshot_win_test.cc b/snapshot/win/module_snapshot_win_test.cc index 6a14cf5e..d9786cfd 100644 --- a/snapshot/win/module_snapshot_win_test.cc +++ b/snapshot/win/module_snapshot_win_test.cc @@ -30,7 +30,6 @@ #include "snapshot/annotation_snapshot.h" #include "snapshot/win/pe_image_reader.h" #include "snapshot/win/process_reader_win.h" -#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -152,7 +151,7 @@ TEST(ModuleSnapshotWinTest, CrashDebugBreak) { #if defined(ARCH_CPU_64_BITS) TEST(ModuleSnapshotWinTest, DontCrashWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::k32Bit); @@ -160,7 +159,7 @@ TEST(ModuleSnapshotWinTest, DontCrashWOW64) { TEST(ModuleSnapshotWinTest, CrashDebugBreakWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::k32Bit); diff --git a/snapshot/win/process_snapshot_win_test.cc b/snapshot/win/process_snapshot_win_test.cc index 8a3e6a49..7192aa85 100644 --- a/snapshot/win/process_snapshot_win_test.cc +++ b/snapshot/win/process_snapshot_win_test.cc @@ -20,7 +20,6 @@ #include "snapshot/win/pe_image_reader.h" #include "snapshot/win/process_reader_win.h" #include "test/errors.h" -#include "test/gtest_disabled.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" #include "util/file/file_io.h" @@ -120,7 +119,7 @@ TEST(ProcessSnapshotTest, CrashpadInfoChild) { #if defined(ARCH_CPU_64_BITS) TEST(ProcessSnapshotTest, CrashpadInfoChildWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestImageReaderChild(TestPaths::Architecture::k32Bit); diff --git a/test/BUILD.gn b/test/BUILD.gn index fb99bce6..7f448632 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -25,8 +25,6 @@ static_library("test") { "filesystem.cc", "filesystem.h", "gtest_death.h", - "gtest_disabled.cc", - "gtest_disabled.h", "hex_string.cc", "hex_string.h", "main_arguments.cc", diff --git a/test/gtest_disabled.cc b/test/gtest_disabled.cc deleted file mode 100644 index fab6802a..00000000 --- a/test/gtest_disabled.cc +++ /dev/null @@ -1,83 +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 "test/gtest_disabled.h" - -#include <stdio.h> - -#include "base/format_macros.h" -#include "base/logging.h" -#include "base/strings/stringprintf.h" - -namespace crashpad { -namespace test { - -namespace { - -DisabledTestGtestEnvironment* g_instance; - -} // namespace - -// static -DisabledTestGtestEnvironment* DisabledTestGtestEnvironment::Get() { - if (!g_instance) { - g_instance = new DisabledTestGtestEnvironment(); - } - return g_instance; -} - -void DisabledTestGtestEnvironment::DisabledTest() { - const testing::TestInfo* test_info = - testing::UnitTest::GetInstance()->current_test_info(); - std::string disabled_test = base::StringPrintf( - "%s.%s", test_info->test_case_name(), test_info->name()); - - // Show a DISABLED message using a format similar to gtest, along with a hint - // explaining that OK or FAILED will also appear. - printf( - "This test has been disabled dynamically.\n" - "It will appear as both DISABLED and OK or FAILED.\n" - "[ DISABLED ] %s\n", - disabled_test.c_str()); - - disabled_tests_.push_back(disabled_test); -} - -DisabledTestGtestEnvironment::DisabledTestGtestEnvironment() - : testing::Environment(), - disabled_tests_() { - DCHECK(!g_instance); -} - -DisabledTestGtestEnvironment::~DisabledTestGtestEnvironment() { - DCHECK_EQ(this, g_instance); - g_instance = nullptr; -} - -void DisabledTestGtestEnvironment::TearDown() { - if (!disabled_tests_.empty()) { - printf( - "[ DISABLED ] %" PRIuS " dynamically disabled test%s, listed below:\n" - "[ DISABLED ] %s also counted in PASSED or FAILED below.\n", - disabled_tests_.size(), - disabled_tests_.size() == 1 ? "" : "s", - disabled_tests_.size() == 1 ? "This test is" : "These tests are"); - for (const std::string& disabled_test : disabled_tests_) { - printf("[ DISABLED ] %s\n", disabled_test.c_str()); - } - } -} - -} // namespace test -} // namespace crashpad diff --git a/test/gtest_disabled.h b/test/gtest_disabled.h deleted file mode 100644 index 9415cba2..00000000 --- a/test/gtest_disabled.h +++ /dev/null @@ -1,87 +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. - -#ifndef CRASHPAD_TEST_GTEST_DISABLED_H_ -#define CRASHPAD_TEST_GTEST_DISABLED_H_ - -#include <string> -#include <vector> - -#include "base/macros.h" -#include "gtest/gtest.h" - -//! \file - -namespace crashpad { -namespace test { - -//! \brief Provides support for dynamically disabled gtest tests. -//! -//! A test runner must register this with gtest as follows prior to calling -//! `RUN_ALL_TESTS()`: -//! \code -//! testing::AddGlobalTestEnvironment( -//! crashpad::test::DisabledTestGtestEnvironment::Get()); -//! \endcode -class DisabledTestGtestEnvironment final : public testing::Environment { - public: - //! \brief Returns the DisabledTestGtestEnvironment singleton instance, - //! creating it if necessary. - static DisabledTestGtestEnvironment* Get(); - - //! \brief Displays a message about a test being disabled, and arranges for - //! this information to be duplicated in TearDown(). - //! - //! This method is for the internal use of the DISABLED_TEST() macro. Do not - //! call it directly, use the macro instead. - void DisabledTest(); - - private: - DisabledTestGtestEnvironment(); - ~DisabledTestGtestEnvironment() override; - - // testing::Environment: - void TearDown() override; - - std::vector<std::string> disabled_tests_; - - DISALLOW_COPY_AND_ASSIGN(DisabledTestGtestEnvironment); -}; - -} // namespace test -} // namespace crashpad - -//! \brief Displays a message about a test being disabled, and returns early. -//! -//! gtest only provides a mechanism for tests to be disabled statically, by -//! prefixing test case names or test names with `DISABLED_`. When it is -//! necessary to disable tests dynamically, gtest provides no assistance. This -//! macro displays a message about the disabled test and returns early. The -//! dynamically disabled test will also be displayed during gtest global test -//! environment tear-down before the test executable exits. -//! -//! This macro may only be invoked from the context of a gtest test. -//! -//! There’s a long-standing <a -//! href="https://groups.google.com/d/topic/googletestframework/Nwh3u7YFuN4">gtest -//! feature request</a> to provide this functionality directly in gtest, but -//! since it hasn’t been implemented, this macro provides a local mechanism to -//! achieve it. -#define DISABLED_TEST() \ - do { \ - ::crashpad::test::DisabledTestGtestEnvironment::Get()->DisabledTest(); \ - return; \ - } while (false) - -#endif // CRASHPAD_TEST_GTEST_DISABLED_H_ diff --git a/test/gtest_main.cc b/test/gtest_main.cc index ebdbeb9d..5a54691f 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -14,7 +14,6 @@ #include "build/build_config.h" #include "gtest/gtest.h" -#include "test/gtest_disabled.h" #include "test/main_arguments.h" #include "test/multiprocess_exec.h" @@ -51,8 +50,6 @@ bool GetChildTestFunctionName(std::string* child_func_name) { int main(int argc, char* argv[]) { crashpad::test::InitializeMainArguments(argc, argv); - testing::AddGlobalTestEnvironment( - crashpad::test::DisabledTestGtestEnvironment::Get()); std::string child_func_name; if (GetChildTestFunctionName(&child_func_name)) { diff --git a/test/test.gyp b/test/test.gyp index 8101f8f2..d00256a7 100644 --- a/test/test.gyp +++ b/test/test.gyp @@ -37,8 +37,6 @@ 'filesystem.cc', 'filesystem.h', 'gtest_death.h', - 'gtest_disabled.cc', - 'gtest_disabled.h', 'hex_string.cc', 'hex_string.h', 'linux/fake_ptrace_connection.cc', diff --git a/util/file/directory_reader_test.cc b/util/file/directory_reader_test.cc index f03669e2..812deaf1 100644 --- a/util/file/directory_reader_test.cc +++ b/util/file/directory_reader_test.cc @@ -22,7 +22,6 @@ #include "base/strings/utf_string_conversions.h" #include "gtest/gtest.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" @@ -48,7 +47,7 @@ TEST(DirectoryReader, BadPaths) { TEST(DirectoryReader, BadPaths_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -144,7 +143,7 @@ TEST(DirectoryReader, FilesAndDirectories) { TEST(DirectoryReader, FilesAndDirectories_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestFilesAndDirectories(true); diff --git a/util/file/filesystem_test.cc b/util/file/filesystem_test.cc index 3430c3f9..37a9290b 100644 --- a/util/file/filesystem_test.cc +++ b/util/file/filesystem_test.cc @@ -21,7 +21,6 @@ #include "gtest/gtest.h" #include "test/errors.h" #include "test/filesystem.h" -#include "test/gtest_disabled.h" #include "test/scoped_temp_dir.h" #include "util/misc/time.h" @@ -93,7 +92,7 @@ TEST(Filesystem, FileModificationTime) { TEST(Filesystem, FileModificationTime_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -224,7 +223,7 @@ TEST(Filesystem, MoveFileOrDirectory) { TEST(Filesystem, MoveFileOrDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -302,7 +301,7 @@ TEST(Filesystem, IsRegularFile) { TEST(Filesystem, IsRegularFile_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -344,7 +343,7 @@ TEST(Filesystem, IsDirectory) { TEST(Filesystem, IsDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -393,7 +392,7 @@ TEST(Filesystem, RemoveFile) { TEST(Filesystem, RemoveFile_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; @@ -450,7 +449,7 @@ TEST(Filesystem, RemoveDirectory) { TEST(Filesystem, RemoveDirectory_SymbolicLinks) { if (!CanCreateSymbolicLinks()) { - DISABLED_TEST(); + GTEST_SKIP(); } ScopedTempDir temp_dir; diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc index 59aaa7a9..a43358d4 100644 --- a/util/win/process_info_test.cc +++ b/util/win/process_info_test.cc @@ -26,7 +26,6 @@ #include "build/build_config.h" #include "gtest/gtest.h" #include "test/errors.h" -#include "test/gtest_disabled.h" #include "test/scoped_temp_dir.h" #include "test/test_paths.h" #include "test/win/child_launcher.h" @@ -203,7 +202,7 @@ TEST(ProcessInfo, OtherProcess) { #if defined(ARCH_CPU_64_BITS) TEST(ProcessInfo, OtherProcessWOW64) { if (!TestPaths::Has32BitBuildArtifacts()) { - DISABLED_TEST(); + GTEST_SKIP(); } TestOtherProcess(TestPaths::Architecture::k32Bit); From d8f85829b07bd807336684a6b2034643af39cbb6 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 11 Oct 2019 15:13:37 -0700 Subject: [PATCH 274/401] linux: fix split stack test Previously, page_addr sometimes ended up being in the current stack frame, causing a segfault when write protecting it. Reach another page up the stack and add an extra stack page for wiggle room. The test consistently fails on linux-chromeos bots: https://ci.chromium.org/p/chromium/builders/try/linux-chromeos-rel/373920 Change-Id: I5e2aa8c54555ef559251a14b0310a24131c9f17a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1857500 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- snapshot/linux/process_reader_linux_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snapshot/linux/process_reader_linux_test.cc b/snapshot/linux/process_reader_linux_test.cc index a69a4c02..5b572361 100644 --- a/snapshot/linux/process_reader_linux_test.cc +++ b/snapshot/linux/process_reader_linux_test.cc @@ -427,7 +427,7 @@ class ChildWithSplitStackTest : public Multiprocess { } void MultiprocessChild() override { - const LinuxVMSize stack_size = page_size_ * 3; + const LinuxVMSize stack_size = page_size_ * 4; GrowStack(stack_size, reinterpret_cast<LinuxVMAddress>(&stack_size)); } @@ -440,7 +440,7 @@ class ChildWithSplitStackTest : public Multiprocess { } else { // Write-protect a page on our stack to split up the mapping LinuxVMAddress page_addr = - stack_address - (stack_address % page_size_) + page_size_; + stack_address - (stack_address % page_size_) + 2 * page_size_; ASSERT_EQ( mprotect(reinterpret_cast<void*>(page_addr), page_size_, PROT_READ), 0) From 7289acb78a6d67de372b49f6467947043d1ec0b3 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 14 Oct 2019 14:14:06 -0700 Subject: [PATCH 275/401] linux: don't assume vdso exists AT_SYSINFO_EHDR may be defined even if no vdso is used. e.g. 32-bit ARM processes have a vdso on 64-bit ARM cpus, but not on 32-bit cpus. Change-Id: I4d9ce029bb47efc33ea16cb4c5c2055c1b9330c9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1860935 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/linux/auxiliary_vector_test.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/util/linux/auxiliary_vector_test.cc b/util/linux/auxiliary_vector_test.cc index d4cfcb74..00af5abe 100644 --- a/util/linux/auxiliary_vector_test.cc +++ b/util/linux/auxiliary_vector_test.cc @@ -120,8 +120,9 @@ void TestAgainstCloneOrSelf(pid_t pid) { #if defined(AT_SYSINFO_EHDR) LinuxVMAddress vdso_addr; - ASSERT_TRUE(aux.GetValue(AT_SYSINFO_EHDR, &vdso_addr)); - EXPECT_TRUE(mappings.FindMapping(vdso_addr)); + if (aux.GetValue(AT_SYSINFO_EHDR, &vdso_addr)) { + EXPECT_TRUE(mappings.FindMapping(vdso_addr)); + } #endif // AT_SYSINFO_EHDR #if defined(AT_EXECFN) From 47a342133d60018f2ffda0037ffe2b5f0d3f7482 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 14 Oct 2019 14:46:20 -0700 Subject: [PATCH 276/401] linux: use boringssl in chromium Or else the uploader will check fail when uploading to https://... Change-Id: I88a765215cc7bff5809b8effd92f4e39bebd1e5b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1860940 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/net/tls.gni | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/net/tls.gni b/util/net/tls.gni index f979b620..eb968450 100644 --- a/util/net/tls.gni +++ b/util/net/tls.gni @@ -18,5 +18,6 @@ declare_args() { # TODO(scottmg): https://crbug.com/crashpad/266 fuchsia:DX-690: BoringSSL # was removed from the Fuchsia SDK. Re-enable it when we have a way to acquire # a BoringSSL lib again. - crashpad_use_boringssl_for_http_transport_socket = crashpad_is_in_fuchsia + crashpad_use_boringssl_for_http_transport_socket = + crashpad_is_in_fuchsia || (crashpad_is_linux && crashpad_is_in_chromium) } From 661a07a41b8809b9df32914c11542a0c76e709d5 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 18 Oct 2019 07:28:43 -0700 Subject: [PATCH 277/401] linux: add deps for boringssl in chromium Change-Id: Icc0acddd7218c85950874555405c8f8b5c3149dd Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1869251 Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/BUILD.gn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index dec7d5c4..c233f96f 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -281,7 +281,7 @@ static_library("util") { if (crashpad_use_boringssl_for_http_transport_socket) { defines += [ "CRASHPAD_USE_BORINGSSL" ] - if (crashpad_is_in_fuchsia) { + if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { deps += [ "//third_party/boringssl" ] } else { libs = [ @@ -545,7 +545,7 @@ if (!crashpad_is_android) { ] defines = [ "CRASHPAD_USE_BORINGSSL" ] - if (crashpad_is_in_fuchsia) { + if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { deps += [ "//third_party/boringssl" ] } else { libs = [ From b2e26bc4558291a61474d9ac1d5f63222b5e8cc1 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Wed, 23 Oct 2019 12:50:17 -0700 Subject: [PATCH 278/401] fuchsia: Fix fidl_init_txn_header link error Add missing/new fidl_base/txn_header.c to fidl_base library in Fuchsia build. However, that transitively includes files that use static_assert via assert.h, which is a C11 feature. Per https://fuchsia.googlesource.com/fuchsia/+/master/docs/development/api/c.md#Language-versions-C-1 Fuchsia does not aim to support C99, so change the build setting in mini_chromium as well in https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/1876894 Includes mini_chromium roll: 2298dbe9d0b3213720ac0e5418ad0013a19aeb5d Change cflags_c from c99 to c11 63dfdbd690244c58c1595543806bafd5e5f8aabd Adds support for codesigning iOS app bundles. ae8e6c54b9a6ea2fd4ff64aab61227d9fad1897e Adds GN rules for ios app bundles. Change-Id: I09c93d5b2b7ae197c8dc95b83e9c467a68ee51f1 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1876893 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- third_party/fuchsia/BUILD.gn | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index ec173470..90c103d0 100644 --- a/DEPS +++ b/DEPS @@ -33,7 +33,7 @@ deps = { '8048ece6c16c91acfe0d36d1d3cc0890ab6e945c', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '660b43a779892e7fdb74d490b54cf37ffe8a978d', + '2298dbe9d0b3213720ac0e5418ad0013a19aeb5d', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 9c25b58d..6398ca55 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -17,10 +17,10 @@ import("../../build/crashpad_buildconfig.gni") if (crashpad_is_in_fuchsia) { group("fuchsia") { public_deps = [ - "//zircon/system/fidl/fuchsia-mem", - "//zircon/system/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c", "//zircon/public/lib/fdio", "//zircon/public/lib/zx", + "//zircon/system/fidl/fuchsia-mem", + "//zircon/system/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c", ] } } else if (crashpad_is_in_chromium) { @@ -88,6 +88,7 @@ if (crashpad_is_in_fuchsia) { "$sdk_pkg_path/fidl_base/message.cc", "$sdk_pkg_path/fidl_base/message_buffer.cc", "$sdk_pkg_path/fidl_base/message_builder.cc", + "$sdk_pkg_path/fidl_base/txn_header.c", "$sdk_pkg_path/fidl_base/validating.cc", "$sdk_pkg_path/fidl_base/visitor.h", "$sdk_pkg_path/fidl_base/walker.cc", From cea103fb7d3047c6ebc16c1da6076bbce653c0e7 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 22 Oct 2019 16:56:26 -0400 Subject: [PATCH 279/401] mac: Fix ProcessTypes.DyldImagesSelf with 10.14 SDK on 10.12 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current 10.14 SDK is numbered 101404, which is greater than MAC_OS_X_VERSION_10_14 (101400). That was causing the test to unintentionally fall into the “unlisted SDK” branch of the #if cascade due to testing SDK <= MAC_OS_X_VERSION_10_14. This is corrected by testing SDK < MAC_OS_X_VERSION_10_15 instead. Bug: chromium:1016314, crashpad:310 Change-Id: If062e8fca92ae105924addf10c3e2fde162448cf Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1872636 Reviewed-by: Robert Sesek <rsesek@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- snapshot/mac/process_types_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapshot/mac/process_types_test.cc b/snapshot/mac/process_types_test.cc index 8523b9cb..0ad28697 100644 --- a/snapshot/mac/process_types_test.cc +++ b/snapshot/mac/process_types_test.cc @@ -130,7 +130,7 @@ TEST(ProcessTypes, DyldImagesSelf) { test_expected_size_for_version_matches_sdk_sizeof = mac_os_x_minor_version == 12; #elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 && \ - MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_14 + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_15 test_expected_size_for_version_matches_sdk_sizeof = mac_os_x_minor_version >= 13 && mac_os_x_minor_version <= 14; #else From 1b60c8172c783040b86c3c6960aba4df73990bc5 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 30 Oct 2019 15:27:03 -0700 Subject: [PATCH 280/401] commit test ssl certificate to testdata Chromium requires build artifacts to be generated deterministically so commit a long-lived (10 years) test certificate to the repository. Change-Id: I7a6e2441f506196ca58fbbf757648fa0ac70bc9a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1872188 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- BUILD.gn | 9 ++--- util/BUILD.gn | 14 ------- util/net/generate_test_server_key.py | 37 ++++++++++++++----- util/net/http_transport_test.cc | 18 +++++---- util/net/testdata/crashpad_util_test_cert.pem | 21 +++++++++++ util/net/testdata/crashpad_util_test_key.pem | 30 +++++++++++++++ 6 files changed, 93 insertions(+), 36 deletions(-) create mode 100644 util/net/testdata/crashpad_util_test_cert.pem create mode 100644 util/net/testdata/crashpad_util_test_key.pem diff --git a/BUILD.gn b/BUILD.gn index 10850c6c..d1a2b721 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -103,15 +103,14 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { ] if (crashpad_use_boringssl_for_http_transport_socket) { - deps += [ "util:generate_test_server_key" ] resources += [ { - path = "$root_out_dir/crashpad_util_test_cert.pem" - dest = "crashpad_util_test_cert.pem" + path = "util/net/testdata/crashpad_util_test_cert.pem" + dest = "util/net/testdata/crashpad_util_test_cert.pem" }, { - path = "$root_out_dir/crashpad_util_test_key.pem" - dest = "crashpad_util_test_key.pem" + path = "util/net/testdata/crashpad_util_test_key.pem" + dest = "util/net/testdata/crashpad_util_test_key.pem" }, ] } diff --git a/util/BUILD.gn b/util/BUILD.gn index c233f96f..d225f1dc 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -505,17 +505,6 @@ static_library("util") { } } -if (crashpad_use_boringssl_for_http_transport_socket) { - action("generate_test_server_key") { - script = "net/generate_test_server_key.py" - outputs = [ - "$root_out_dir/crashpad_util_test_cert.pem", - "$root_out_dir/crashpad_util_test_key.pem", - ] - data = outputs - } -} - if (!crashpad_is_android) { crashpad_executable("http_transport_test_server") { testonly = true @@ -540,9 +529,6 @@ if (!crashpad_is_android) { } if (crashpad_use_boringssl_for_http_transport_socket) { - data_deps = [ - ":generate_test_server_key", - ] defines = [ "CRASHPAD_USE_BORINGSSL" ] if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { diff --git a/util/net/generate_test_server_key.py b/util/net/generate_test_server_key.py index 6e6340e3..31d73c9a 100755 --- a/util/net/generate_test_server_key.py +++ b/util/net/generate_test_server_key.py @@ -16,13 +16,32 @@ import os import subprocess +import sys -# GN requires a Python script for actions, so this just wraps the openssl -# command needed to generate a test private key and a certificate. These names -# must correspond to what TestPaths::BuildArtifact() constructs. -key = 'crashpad_util_test_key.pem' -cert = 'crashpad_util_test_cert.pem' -subprocess.check_call( - ['openssl', 'req', '-x509', '-nodes', '-subj', '/CN=localhost', - '-days', '365', '-newkey', 'rsa:2048', '-keyout', key, '-out', cert], - stderr=open(os.devnull, 'w')) +testdata = os.path.join(os.path.dirname(__file__), 'testdata') +key = os.path.join(testdata, 'crashpad_util_test_key.pem') +cert = os.path.join(testdata, 'crashpad_util_test_cert.pem') + +with open(cert, 'w') as cert_file, open(key, 'w') as key_file: + MESSAGE = 'DO NOT EDIT: This file was auto-generated by ' + __file__ + '\n\n' + cert_file.write(MESSAGE) + key_file.write(MESSAGE) + + proc = subprocess.Popen( + ['openssl', 'req', '-x509', '-nodes', '-subj', '/CN=localhost', + '-days', '3650', '-newkey', 'rsa:2048', '-keyout', '-'], + stderr=open(os.devnull, 'w'), stdout=subprocess.PIPE) + + contents = proc.communicate()[0] + dest = sys.stderr + for line in contents.splitlines(True): + if line.startswith("-----BEGIN PRIVATE KEY-----"): + dest = key_file + elif line.startswith("-----BEGIN CERTIFICATE-----"): + dest = cert_file + elif line.startswith("-----END"): + dest.write(line) + dest = sys.stderr + continue + + dest.write(line) diff --git a/util/net/http_transport_test.cc b/util/net/http_transport_test.cc index f7888c08..7c5ca2f2 100644 --- a/util/net/http_transport_test.cc +++ b/util/net/http_transport_test.cc @@ -81,15 +81,14 @@ class HTTPTransportTestFixture : public MultiprocessExec { SetChildCommand(server_path, nullptr); } else { std::vector<std::string> args; - cert_ = TestPaths::BuildArtifact(FILE_PATH_LITERAL("util"), - FILE_PATH_LITERAL("cert"), - TestPaths::FileType::kCertificate); + cert_ = TestPaths::TestDataRoot().Append( + FILE_PATH_LITERAL("util/net/testdata/crashpad_util_test_cert.pem")); args.push_back(ToUTF8IfWin(cert_.value())); - args.emplace_back(ToUTF8IfWin( - TestPaths::BuildArtifact(FILE_PATH_LITERAL("util"), - FILE_PATH_LITERAL("key"), - TestPaths::FileType::kCertificate) - .value())); + args.emplace_back( + ToUTF8IfWin(TestPaths::TestDataRoot() + .Append(FILE_PATH_LITERAL( + "util/net/testdata/crashpad_util_test_key.pem")) + .value())); SetChildCommand(server_path, &args); scheme_and_host_ = "https://localhost"; } @@ -371,6 +370,9 @@ TEST_P(HTTPTransport, Upload33k_LengthUnknown) { // lacking libcrypto.so.1.1, so disabled there for now. On Mac, they could also // likely be enabled relatively easily, if HTTPTransportMac learned to respect // the user-supplied cert. +// +// If tests with boringssl are failing because of expired certificates, try +// re-running generate_test_server_key.py. INSTANTIATE_TEST_SUITE_P(HTTPTransport, HTTPTransport, testing::Values(FILE_PATH_LITERAL("http"), diff --git a/util/net/testdata/crashpad_util_test_cert.pem b/util/net/testdata/crashpad_util_test_cert.pem new file mode 100644 index 00000000..5a2261e2 --- /dev/null +++ b/util/net/testdata/crashpad_util_test_cert.pem @@ -0,0 +1,21 @@ +DO NOT EDIT: This file was auto-generated by ./util/net/generate_test_server_key.py + +-----BEGIN CERTIFICATE----- +MIIDCDCCAfCgAwIBAgITF9h5BaPfzje590HrE1UF+f9PVDANBgkqhkiG9w0BAQsF +ADAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTkxMDMwMjIyNDE4WhcNMjkxMDI3 +MjIyNDE4WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCrT0iXfixTPH6nBxgvCgiKkSTeVTSvfhcoUYA7yPZj/1XH +VYfECoGyvFN4/5g/GL4c721XZmI92Twg2Oa3HksRY8VlNXGNwqbt+wftSLOz+dOE +bsJ3+NsBtXuaIphFPA9u0h+yrplBtM/dxLTW5v8e3OuEMBXa+94dp4y78u21UkzM +uWB66tduT7/f0S9P68XhksYwwwvCn5lu258wHKNM5mb4CTwOcUgyyprlS2FS3Fsx +pIsg9wDfQy5rHINxcZGZZ8Ht4KOJ7egwhfiP4XEiLK6+5DZoOQtrkEUFfLL4i5sx ++eOeD12GP+Dxs6KHYoejGftNx/7U0E2GVMWwWzstAgMBAAGjUzBRMB0GA1UdDgQW +BBT8y2bnyty/YWcvzlE9JIAPG7/q4DAfBgNVHSMEGDAWgBT8y2bnyty/YWcvzlE9 +JIAPG7/q4DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCF+R21 +Cd1fgITfhYJE7JAV3jLfact5h/2MP5UwgtODfZt2Idwxs8qqwPB0g7WQqEjrPfTv +6y90AEwr2L8e+wXGnTKtWelCqzztFGov4Hj+rd158eOmEo0IPGrx8dwqLQbw91uU +cq4onf5iuHkOt99TmIqVYn2zaOHbOF2YYyU052X+9XE/Z5fhibX5THfEG3w0+XM6 +aKEGIM/MxfVaLA8yDXFxhDXHBrH+QAAXTQaC8exnp+po/psyJARD0sM509MeTdAv +po9JyIzesNAsLW4I7kL8I5i8e+WN79lX2jgwaWMxPmHadYN3mtoltpmFM40oFN6q +8wjuU07eN/G79c3B +-----END CERTIFICATE----- diff --git a/util/net/testdata/crashpad_util_test_key.pem b/util/net/testdata/crashpad_util_test_key.pem new file mode 100644 index 00000000..b0d69731 --- /dev/null +++ b/util/net/testdata/crashpad_util_test_key.pem @@ -0,0 +1,30 @@ +DO NOT EDIT: This file was auto-generated by ./util/net/generate_test_server_key.py + +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrT0iXfixTPH6n +BxgvCgiKkSTeVTSvfhcoUYA7yPZj/1XHVYfECoGyvFN4/5g/GL4c721XZmI92Twg +2Oa3HksRY8VlNXGNwqbt+wftSLOz+dOEbsJ3+NsBtXuaIphFPA9u0h+yrplBtM/d +xLTW5v8e3OuEMBXa+94dp4y78u21UkzMuWB66tduT7/f0S9P68XhksYwwwvCn5lu +258wHKNM5mb4CTwOcUgyyprlS2FS3FsxpIsg9wDfQy5rHINxcZGZZ8Ht4KOJ7egw +hfiP4XEiLK6+5DZoOQtrkEUFfLL4i5sx+eOeD12GP+Dxs6KHYoejGftNx/7U0E2G +VMWwWzstAgMBAAECggEANEgJDnrqSijfOlh27/wu6SMszlHQt3JS3PIqoZROZexK +IICg45qVRJgnHXlb3H3Pn4MOqqrLdraynA+2MdKj9FWvq5io5CuwyFZhb/BNL7Mh +83veC8E+DYJ2i27da9vNlfO4ys5wZVYqTjM3QZLT73Zaxkfqk59khUZaNA4Kr9hD +EBs9gaDMATyIAN5eAbYTVxgobZ+7OjCNmQ46x2KOg6Wwg/ZQEXtqFoDB3aCNVfTz +OxlLb5XWF9PvqW0p1wFpF0XEDipkVtjorjp3mHXRuq0gS9Gev1ChQej1yVqMee9J +jnVK0k7qZw4WLStxBjHqWlBnYLcXLb4f2c6cssA6YQKBgQDfqtYFjU3HCeoRaAoP +MWTSW2PX8fitnp0O4e1yHymDgtirepvPL8pa7rTBkHuR6lfXNjY0qD0NPsbr81nG +kNv/btLOK1YPw6f468S6DMsOzGPIWWE+jkhF/1iUTMUQLvOM3lCLEi0ayZ26yx1T +F2wO2u1kGc1eJ8wn6TccsYiguQKBgQDEEt7eGQMkxLFV4N5e5iunHBvQg+EgfLZZ +bnuftwruqafmCht/BZgmKQD+e6B6h3nC/iaKET101zpWL95x7Ayd1+mg6Rmdzl87 +ctftScrNLYUTl36BuhP82Y9HvLgf20xrEwBGivc0QtqhMAz/DJoknEM/29LmWEsZ +VwvWQxhsFQKBgQCrOcJMT8d6Fznsh2QkC2EutK3ztBb2+xUrPoQjOH30YqfyZpN/ +Agv8nv8bq7sdknQamjLXDvBmAmgQW6SfoWf53OJe2Mgym0stAXkCIScWNhwxVVNf +q1bi1z79kOPPptHmRo8MWCbVegFY7YOOh8C+gpT3a9VPPlJJP31kZvi8aQKBgDcD +ZGzEb9FdLrR9x2axBgZ5KIS0u/G1jCRDj4Qcg4C7MVSl+VkGZM4wKws7/KbkZBGF +5aJPfALQcJnGDI/CPzf6YJ65SGqygJ3ZdyQo1DIFV5VLqD8Vyo3jLQRfuvmVOjfA +uQ8R5pJPP7CCHuNg0c772RKNxvrCQy/08GlJogyRAoGAK6A/8r/iDRJipJSOZdCl +MreiJvjFOQrORhy+TeDGn02EHK0lijzj1I7SlgfUDLWVnQpBlk12wV6aHGUj2NlG +Ctk15MFs6gggPV1Fmt6PeviE1e9E4+SDWX35Jhe8JDIqxdgZ0HW/S9Nl4Xt3owhw +/DSneMQd7X0Tdq7lesJjd3o= +-----END PRIVATE KEY----- From 272c4bb64e2761448e6e84c665a9a88648efacef Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Tue, 5 Nov 2019 09:59:38 -0800 Subject: [PATCH 281/401] fuchsia: Add missing transformer.cc to fidl_base Fix fidl_base build, again. Fixes broken tryjobs as seen in https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1872188. Change-Id: Iaec1613b3b335fac501227b7a86134309f52d7f3 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1899650 Reviewed-by: Francois Rousseau <frousseau@google.com> Commit-Queue: Scott Graham <scottmg@chromium.org> --- third_party/fuchsia/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 6398ca55..e96ec664 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -88,6 +88,7 @@ if (crashpad_is_in_fuchsia) { "$sdk_pkg_path/fidl_base/message.cc", "$sdk_pkg_path/fidl_base/message_buffer.cc", "$sdk_pkg_path/fidl_base/message_builder.cc", + "$sdk_pkg_path/fidl_base/transformer.cc", "$sdk_pkg_path/fidl_base/txn_header.c", "$sdk_pkg_path/fidl_base/validating.cc", "$sdk_pkg_path/fidl_base/visitor.h", From 27322abb7ec40f46020f93b3814c19f77ea2ccfb Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Tue, 5 Nov 2019 14:31:17 -0800 Subject: [PATCH 282/401] [net] specify parameter name in parameterized test suite * this renders as "HTTPTransport/HTTPTransport.ValidFormData_Gzip/http" instead of the default "HTTPTransport/HTTPTransport.ValidFormData_Gzip/0" * switch the parameter type from a base::FilePath::StringType to a string Change-Id: I19743966406f92176c566827d74a79aef5a87bb5 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1900324 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Francois Rousseau <frousseau@google.com> --- util/net/http_transport_test.cc | 44 +++++++++++++++++---------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/util/net/http_transport_test.cc b/util/net/http_transport_test.cc index 7c5ca2f2..d6a7675f 100644 --- a/util/net/http_transport_test.cc +++ b/util/net/http_transport_test.cc @@ -54,10 +54,10 @@ std::string ToUTF8IfWin(const std::string& x) { class HTTPTransportTestFixture : public MultiprocessExec { public: - using RequestValidator = - void(*)(HTTPTransportTestFixture*, const std::string&); + using RequestValidator = void (*)(HTTPTransportTestFixture*, + const std::string&); - HTTPTransportTestFixture(const base::FilePath::StringType& scheme, + HTTPTransportTestFixture(const std::string& scheme, const HTTPHeaders& headers, std::unique_ptr<HTTPBodyStream> body_stream, uint16_t http_response_code, @@ -74,9 +74,9 @@ class HTTPTransportTestFixture : public MultiprocessExec { #if defined(OS_WIN) FILE_PATH_LITERAL(".exe") #endif - ); + ); - if (ToUTF8IfWin(scheme) == "http") { + if (scheme == "http") { scheme_and_host_ = "http://localhost"; SetChildCommand(server_path, nullptr); } else { @@ -116,9 +116,8 @@ class HTTPTransportTestFixture : public MultiprocessExec { // 200. const std::string random_string = RandomString(); - ASSERT_TRUE(LoggingWriteFile(WritePipeHandle(), - random_string.c_str(), - random_string.size())); + ASSERT_TRUE(LoggingWriteFile( + WritePipeHandle(), random_string.c_str(), random_string.size())); // Now execute the HTTP request. std::unique_ptr<HTTPTransport> transport(HTTPTransport::Create()); @@ -245,8 +244,7 @@ void ValidFormData(HTTPTransportTestFixture* fixture, EXPECT_EQ(request.substr(body_start), expected); } -class HTTPTransport - : public testing::TestWithParam<base::FilePath::StringType> {}; +class HTTPTransport : public testing::TestWithParam<std::string> {}; TEST_P(HTTPTransport, ValidFormData) { HTTPMultipartBuilder builder; @@ -256,8 +254,8 @@ TEST_P(HTTPTransport, ValidFormData) { HTTPHeaders headers; builder.PopulateContentHeaders(&headers); - HTTPTransportTestFixture test(GetParam(), - headers, builder.GetBodyStream(), 200, &ValidFormData); + HTTPTransportTestFixture test( + GetParam(), headers, builder.GetBodyStream(), 200, &ValidFormData); test.Run(); } @@ -288,8 +286,8 @@ TEST_P(HTTPTransport, ErrorResponse) { HTTPMultipartBuilder builder; HTTPHeaders headers; headers[kContentType] = kTextPlain; - HTTPTransportTestFixture test(GetParam(), headers, builder.GetBodyStream(), - 404, &ErrorResponse); + HTTPTransportTestFixture test( + GetParam(), headers, builder.GetBodyStream(), 404, &ErrorResponse); test.Run(); } @@ -320,13 +318,12 @@ TEST_P(HTTPTransport, UnchunkedPlainText) { headers[kContentType] = kTextPlain; headers[kContentLength] = base::StringPrintf("%" PRIuS, strlen(kTextBody)); - HTTPTransportTestFixture test(GetParam(), - headers, std::move(body_stream), 200, &UnchunkedPlainText); + HTTPTransportTestFixture test( + GetParam(), headers, std::move(body_stream), 200, &UnchunkedPlainText); test.Run(); } -void RunUpload33k(const base::FilePath::StringType& scheme, - bool has_content_length) { +void RunUpload33k(const std::string& scheme, bool has_content_length) { // On macOS, NSMutableURLRequest winds up calling into a CFReadStream’s Read() // callback with a 32kB buffer. Make sure that it’s able to get everything // when enough is available to fill this buffer, requiring more than one @@ -375,12 +372,17 @@ TEST_P(HTTPTransport, Upload33k_LengthUnknown) { // re-running generate_test_server_key.py. INSTANTIATE_TEST_SUITE_P(HTTPTransport, HTTPTransport, - testing::Values(FILE_PATH_LITERAL("http"), - FILE_PATH_LITERAL("https"))); + testing::Values("http", "https"), + [](const testing::TestParamInfo<std::string>& info) { + return info.param; + }); #else INSTANTIATE_TEST_SUITE_P(HTTPTransport, HTTPTransport, - testing::Values(FILE_PATH_LITERAL("http"))); + testing::Values("http"), + [](const testing::TestParamInfo<std::string>& info) { + return info.param; + }); #endif } // namespace From 6dadd492b890f11f236d71b493a084e30e78f358 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 6 Nov 2019 10:00:13 -0800 Subject: [PATCH 283/401] linux: fix proc stat reader flakiness ProcStatReader.Threads is flaky because it relies on an internal, imprecise measurement of boot time. The flaky test asserts that a thread started after the main thread should have a start time >= the main thread. The start time is returned in a timeval, with microsecond precision, but the measurement of boot time requires two system calls and the time between those system calls can be approximately a microsecond. An unlucky event such as a change in system time could make this imprecision arbitrarily bad. This patch lets the caller of ProcStatReader.StartTime() inject the boot time, allowing ProcStatReader to guarantee that threads have correctly ordered time, given the same input boot time. Bug: 1016765 Change-Id: I6e4a944a1d58c3916090bab6a4b99573e71a89fc Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1891588 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/BUILD.gn | 1 + util/linux/proc_stat_reader.cc | 22 +++-------------- util/linux/proc_stat_reader.h | 3 ++- util/linux/proc_stat_reader_test.cc | 30 +++++++++++++++++------ util/misc/time.h | 8 ++++++ util/misc/time_linux.cc | 38 +++++++++++++++++++++++++++++ util/posix/process_info_linux.cc | 9 ++++++- util/util.gyp | 1 + 8 files changed, 83 insertions(+), 29 deletions(-) create mode 100644 util/misc/time_linux.cc diff --git a/util/BUILD.gn b/util/BUILD.gn index d225f1dc..02558909 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -332,6 +332,7 @@ static_library("util") { "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", diff --git a/util/linux/proc_stat_reader.cc b/util/linux/proc_stat_reader.cc index 88658f58..dd663d6c 100644 --- a/util/linux/proc_stat_reader.cc +++ b/util/linux/proc_stat_reader.cc @@ -85,7 +85,8 @@ bool ProcStatReader::SystemCPUTime(timeval* system_time) const { return ReadTimeAtIndex(14, system_time); } -bool ProcStatReader::StartTime(timeval* start_time) const { +bool ProcStatReader::StartTime(const timeval& boot_time, + timeval* start_time) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); timeval time_after_boot; @@ -93,24 +94,7 @@ bool ProcStatReader::StartTime(timeval* start_time) const { return false; } - timespec uptime; - if (clock_gettime(CLOCK_BOOTTIME, &uptime) != 0) { - PLOG(ERROR) << "clock_gettime"; - return false; - } - - timespec current_time; - if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) { - PLOG(ERROR) << "clock_gettime"; - return false; - } - - timespec boot_time_ts; - SubtractTimespec(current_time, uptime, &boot_time_ts); - timeval boot_time_tv; - TimespecToTimeval(boot_time_ts, &boot_time_tv); - timeradd(&boot_time_tv, &time_after_boot, start_time); - + timeradd(&boot_time, &time_after_boot, start_time); return true; } diff --git a/util/linux/proc_stat_reader.h b/util/linux/proc_stat_reader.h index c0b30520..6eae8fbb 100644 --- a/util/linux/proc_stat_reader.h +++ b/util/linux/proc_stat_reader.h @@ -60,11 +60,12 @@ class ProcStatReader { //! \brief Determines the target thread’s start time. //! + //! \param[in] boot_time The kernel boot time. //! \param[out] start_time The time that the thread started. //! //! \return `true` on success, with \a start_time set. Otherwise, `false` with //! a message logged. - bool StartTime(timeval* start_time) const; + bool StartTime(const timeval& boot_time, timeval* start_time) const; private: bool FindColumn(int index, const char** column) const; diff --git a/util/linux/proc_stat_reader_test.cc b/util/linux/proc_stat_reader_test.cc index bc0d65bc..01b9afd7 100644 --- a/util/linux/proc_stat_reader_test.cc +++ b/util/linux/proc_stat_reader_test.cc @@ -21,6 +21,7 @@ #include "base/logging.h" #include "gtest/gtest.h" #include "test/linux/fake_ptrace_connection.h" +#include "util/misc/time.h" #include "util/thread/thread.h" namespace crashpad { @@ -34,8 +35,13 @@ TEST(ProcStatReader, Basic) { ProcStatReader stat; ASSERT_TRUE(stat.Initialize(&connection, getpid())); + timespec boot_time_ts; + ASSERT_TRUE(GetBootTime(&boot_time_ts)); + timeval boot_time; + TimespecToTimeval(boot_time_ts, &boot_time); + timeval start_time; - ASSERT_TRUE(stat.StartTime(&start_time)); + ASSERT_TRUE(stat.StartTime(boot_time, &start_time)); time_t now; time(&now); @@ -56,30 +62,38 @@ pid_t gettid() { return syscall(SYS_gettid); } -void GetStartTime(timeval* start_time) { +void GetStartTime(const timeval& boot_time, timeval* start_time) { FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(getpid())); ProcStatReader stat; ASSERT_TRUE(stat.Initialize(&connection, gettid())); - ASSERT_TRUE(stat.StartTime(start_time)); + ASSERT_TRUE(stat.StartTime(boot_time, start_time)); } class StatTimeThread : public Thread { public: - StatTimeThread(timeval* start_time) : start_time_(start_time) {} + StatTimeThread(const timeval& boot_time, timeval* start_time) + : boot_time_(boot_time), start_time_(start_time) {} private: - void ThreadMain() override { GetStartTime(start_time_); } + void ThreadMain() override { GetStartTime(boot_time_, start_time_); } + + const timeval& boot_time_; timeval* start_time_; }; TEST(ProcStatReader, Threads) { + timespec boot_time_ts; + ASSERT_TRUE(GetBootTime(&boot_time_ts)); + timeval boot_time; + TimespecToTimeval(boot_time_ts, &boot_time); + timeval main_time; - ASSERT_NO_FATAL_FAILURE(GetStartTime(&main_time)); + ASSERT_NO_FATAL_FAILURE(GetStartTime(boot_time, &main_time)); timeval thread_time; - StatTimeThread thread(&thread_time); + StatTimeThread thread(boot_time, &thread_time); thread.Start(); ASSERT_NO_FATAL_FAILURE(thread.Join()); @@ -89,7 +103,7 @@ TEST(ProcStatReader, Threads) { time_t thread_sec, suseconds_t thread_usec) { return (thread_sec > main_sec) || - (thread_sec == main_sec && thread_usec > main_usec); + (thread_sec == main_sec && thread_usec >= main_usec); }, main_time.tv_sec, main_time.tv_usec, diff --git a/util/misc/time.h b/util/misc/time.h index aabe8e64..dffe1a8a 100644 --- a/util/misc/time.h +++ b/util/misc/time.h @@ -69,6 +69,14 @@ void GetTimeOfDay(timeval* tv); #endif // OS_WIN +#if defined(OS_LINUX) || defined(OS_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_ANDROID || DOXYGEN + } // namespace crashpad #endif // CRASHPAD_UTIL_MISC_TIME_H_ diff --git a/util/misc/time_linux.cc b/util/misc/time_linux.cc new file mode 100644 index 00000000..bc73533c --- /dev/null +++ b/util/misc/time_linux.cc @@ -0,0 +1,38 @@ +// 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. + +#include "util/misc/time.h" + +#include "base/logging.h" + +namespace crashpad { + +bool GetBootTime(timespec* boot_time) { + timespec uptime; + if (clock_gettime(CLOCK_BOOTTIME, &uptime) != 0) { + PLOG(ERROR) << "clock_gettime"; + return false; + } + + timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) { + PLOG(ERROR) << "clock_gettime"; + return false; + } + + SubtractTimespec(current_time, uptime, boot_time); + return true; +} + +} // namespace crashpad diff --git a/util/posix/process_info_linux.cc b/util/posix/process_info_linux.cc index 72a2bd70..3ffd96ab 100644 --- a/util/posix/process_info_linux.cc +++ b/util/posix/process_info_linux.cc @@ -23,6 +23,7 @@ #include "util/file/string_file.h" #include "util/linux/proc_stat_reader.h" #include "util/misc/lexing.h" +#include "util/misc/time.h" namespace crashpad { @@ -238,7 +239,13 @@ bool ProcessInfo::StartTime(timeval* start_time) const { if (!reader.Initialize(connection_, pid_)) { return false; } - if (!reader.StartTime(&start_time_)) { + timespec boot_time_ts; + if (!GetBootTime(&boot_time_ts)) { + return false; + } + timeval boot_time; + TimespecToTimeval(boot_time_ts, &boot_time); + if (!reader.StartTime(boot_time, &start_time_)) { return false; } start_time_initialized_.set_valid(); diff --git a/util/util.gyp b/util/util.gyp index b9da2324..82ba3938 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -168,6 +168,7 @@ 'misc/symbolic_constants_common.h', 'misc/time.cc', 'misc/time.h', + 'misc/time_linux.cc', 'misc/time_win.cc', 'misc/tri_state.h', 'misc/uuid.cc', From bd1aa246ca185519dea0af1c5ca11656c41b0c80 Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Mon, 4 Nov 2019 21:19:33 -0500 Subject: [PATCH 284/401] Starts compiling the crashpad_test_test target on iOS. Brings up the subset of tests that pass on iOS without any modifications. Additional tests will be added later as they are updated to pass on iOS. Excludes non-compiling targets from the iOS build so that the default target compiles cleanly. Rolls mini_chromium to cdab1e6263ec7f3f61763efc1dac863f8dc07c80. 2019-11-01 rohitrao Adds GN support for XCTest on iOS. 2019-10-29 rohitrao Fixes for iOS compilation and running on iOS devices. BUG=crashpad:31 Change-Id: I918f10fc941b37fa89b08ce87828dd4299437096 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1895905 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- BUILD.gn | 29 ++++++++++++--- DEPS | 2 +- build/BUILD.gn | 25 +++++++++++-- build/crashpad_buildconfig.gni | 11 +++--- test/BUILD.gn | 68 +++++++++++++++++++++++++++++----- test/gtest_death.h | 6 +-- test/gtest_main.cc | 4 ++ 7 files changed, 119 insertions(+), 26 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index d1a2b721..b1294cfb 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -23,14 +23,18 @@ config("crashpad_config") { if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { test("crashpad_tests") { deps = [ - "client:client_test", - "handler:handler_test", - "minidump:minidump_test", - "snapshot:snapshot_test", "test:gmock_main", "test:test_test", - "util:util_test", ] + if (!crashpad_is_ios) { + deps += [ + "client:client_test", + "handler:handler_test", + "minidump:minidump_test", + "snapshot:snapshot_test", + "util:util_test", + ] + } } if (crashpad_is_in_fuchsia) { @@ -135,6 +139,9 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "client:client_test", "test:gmock_main", ] + if (crashpad_is_ios) { + deps -= [ "client:client_test" ] + } } test("crashpad_handler_test") { @@ -142,6 +149,9 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "handler:handler_test", "test:gtest_main", ] + if (crashpad_is_ios) { + deps -= [ "handler:handler_test" ] + } } test("crashpad_minidump_test") { @@ -149,6 +159,9 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "minidump:minidump_test", "test:gtest_main", ] + if (crashpad_is_ios) { + deps -= [ "minidump:minidump_test" ] + } } test("crashpad_snapshot_test") { @@ -156,6 +169,9 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "snapshot:snapshot_test", "test:gtest_main", ] + if (crashpad_is_ios) { + deps -= [ "snapshot:snapshot_test" ] + } } test("crashpad_test_test") { @@ -170,5 +186,8 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "test:gmock_main", "util:util_test", ] + if (crashpad_is_ios) { + deps -= [ "util:util_test" ] + } } } diff --git a/DEPS b/DEPS index 90c103d0..4cf88253 100644 --- a/DEPS +++ b/DEPS @@ -33,7 +33,7 @@ deps = { '8048ece6c16c91acfe0d36d1d3cc0890ab6e945c', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '2298dbe9d0b3213720ac0e5418ad0013a19aeb5d', + 'cdab1e6263ec7f3f61763efc1dac863f8dc07c80', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/build/BUILD.gn b/build/BUILD.gn index 0ef1127f..bc77bc81 100644 --- a/build/BUILD.gn +++ b/build/BUILD.gn @@ -45,7 +45,26 @@ config("crashpad_fuzzer_flags") { "-fsanitize=fuzzer", ] - ldflags = [ - "-fsanitize=address", - ] + ldflags = [ "-fsanitize=address" ] +} + +if (crashpad_is_ios) { + group("ios_enable_arc") { + if (crashpad_is_in_chromium) { + public_configs = [ "//build/config/compiler:enable_arc" ] + } else if (crashpad_is_standalone) { + public_configs = + [ "//third_party/mini_chromium/mini_chromium/build:ios_enable_arc" ] + } + } + + group("ios_xctest") { + if (crashpad_is_in_chromium) { + public_configs = [ "//build/config/ios:xctest_config" ] + } else if (crashpad_is_standalone) { + public_configs = [ + "//third_party/mini_chromium/mini_chromium/build/ios:xctest_config", + ] + } + } } diff --git a/build/crashpad_buildconfig.gni b/build/crashpad_buildconfig.gni index 7db56d60..e1ef71f2 100644 --- a/build/crashpad_buildconfig.gni +++ b/build/crashpad_buildconfig.gni @@ -23,11 +23,10 @@ declare_args() { } } -assert(crashpad_dependencies == "chromium" || - crashpad_dependencies == "fuchsia" || - crashpad_dependencies == "standalone" || - crashpad_dependencies == "external" || - crashpad_dependencies == "dart") +assert( + crashpad_dependencies == "chromium" || crashpad_dependencies == "fuchsia" || + crashpad_dependencies == "standalone" || + crashpad_dependencies == "external" || crashpad_dependencies == "dart") crashpad_is_in_chromium = crashpad_dependencies == "chromium" crashpad_is_in_fuchsia = crashpad_dependencies == "fuchsia" @@ -37,6 +36,7 @@ crashpad_is_standalone = crashpad_dependencies == "standalone" if (crashpad_is_in_chromium) { crashpad_is_mac = is_mac + crashpad_is_ios = is_ios crashpad_is_win = is_win crashpad_is_linux = is_linux crashpad_is_android = is_android @@ -57,6 +57,7 @@ if (crashpad_is_in_chromium) { import("../third_party/mini_chromium/mini_chromium/build/platform.gni") } crashpad_is_mac = mini_chromium_is_mac + crashpad_is_ios = mini_chromium_is_ios crashpad_is_win = mini_chromium_is_win crashpad_is_linux = mini_chromium_is_linux crashpad_is_android = mini_chromium_is_android diff --git a/test/BUILD.gn b/test/BUILD.gn index 7f448632..5159744b 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -43,13 +43,36 @@ static_library("test") { "test_paths.h", ] + if (crashpad_is_ios) { + sources -= [ + "errors.cc", + "errors.h", + "file.cc", + "file.h", + "filesystem.cc", + "filesystem.h", + "multiprocess.h", + "multiprocess_exec.cc", + "multiprocess_exec.h", + "process_type.cc", + "process_type.h", + "scoped_guarded_page.h", + "scoped_module_handle.cc", + "scoped_module_handle.h", + "scoped_temp_dir.cc", + "scoped_temp_dir.h", + "test_paths.cc", + "test_paths.h", + ] + } + if (crashpad_is_posix || crashpad_is_fuchsia) { sources += [ "scoped_guarded_page_posix.cc", "scoped_temp_dir_posix.cc", ] - if (!crashpad_is_fuchsia) { + if (!crashpad_is_fuchsia && !crashpad_is_ios) { sources += [ "multiprocess_exec_posix.cc", "multiprocess_posix.cc", @@ -118,6 +141,13 @@ static_library("test") { "../util", ] + if (crashpad_is_ios) { + deps -= [ + "../compat", + "../util", + ] + } + if (crashpad_is_mac) { libs = [ "bsm" ] deps += [ @@ -152,9 +182,18 @@ source_set("test_test") { "test_paths_test.cc", ] + if (crashpad_is_ios) { + sources -= [ + "multiprocess_exec_test.cc", + "scoped_guarded_page_test.cc", + "scoped_temp_dir_test.cc", + "test_paths_test.cc", + ] + } + # 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) { + if (crashpad_is_posix && !crashpad_is_fuchsia && !crashpad_is_ios) { sources += [ "multiprocess_posix_test.cc" ] } @@ -181,16 +220,27 @@ source_set("test_test") { data_deps = [ ":crashpad_test_test_multiprocess_exec_test_child", ] + + if (crashpad_is_ios) { + deps -= [ + "../compat", + "../util", + ] + + data_deps -= [ ":crashpad_test_test_multiprocess_exec_test_child" ] + } } -crashpad_executable("crashpad_test_test_multiprocess_exec_test_child") { - sources = [ - "multiprocess_exec_test_child.cc", - ] +if (!crashpad_is_ios) { + crashpad_executable("crashpad_test_test_multiprocess_exec_test_child") { + sources = [ + "multiprocess_exec_test_child.cc", + ] - deps = [ - "../third_party/mini_chromium:base", - ] + deps = [ + "../third_party/mini_chromium:base", + ] + } } static_library("gmock_main") { diff --git a/test/gtest_death.h b/test/gtest_death.h index 69f6361e..f205a2f1 100644 --- a/test/gtest_death.h +++ b/test/gtest_death.h @@ -25,7 +25,7 @@ //! \file -#if defined(OS_MACOSX) || DOXYGEN +#if (defined(OS_MACOSX) && !defined(OS_IOS)) || DOXYGEN //! \brief Wraps the gtest `ASSERT_DEATH_IF_SUPPORTED()` macro to make //! assertions about death caused by crashes. @@ -73,14 +73,14 @@ regex); \ } while (false) -#else // OS_MACOSX +#else // OS_MACOSX && !OS_IOS #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_MACOSX +#endif // OS_MACOSX && !OS_IOS #if !(!defined(MINI_CHROMIUM_BASE_LOGGING_H_) && \ defined(OFFICIAL_BUILD) && \ diff --git a/test/gtest_main.cc b/test/gtest_main.cc index 5a54691f..e65f9214 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -33,6 +33,7 @@ namespace { +#if !defined(OS_IOS) bool GetChildTestFunctionName(std::string* child_func_name) { constexpr size_t arg_length = sizeof(crashpad::test::internal::kChildTestFunction) - 1; @@ -45,17 +46,20 @@ bool GetChildTestFunctionName(std::string* child_func_name) { } return false; } +#endif // !OS_IOS } // namespace int main(int argc, char* argv[]) { crashpad::test::InitializeMainArguments(argc, argv); +#if !defined(OS_IOS) std::string child_func_name; if (GetChildTestFunctionName(&child_func_name)) { return crashpad::test::internal::CheckedInvokeMultiprocessChild( child_func_name); } +#endif // !OS_IOS #if defined(CRASHPAD_IS_IN_CHROMIUM) From 93f8aa8df9899db99c9d7d98d6f7c5eeb490e15d Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 7 Nov 2019 19:29:58 -0800 Subject: [PATCH 285/401] posix: fix parameter name in signals test Change-Id: I6e998571171c9a725d88a9529c73d01c62ee984f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1905146 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/posix/signals_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/posix/signals_test.cc b/util/posix/signals_test.cc index f46e331e..58bfa8f8 100644 --- a/util/posix/signals_test.cc +++ b/util/posix/signals_test.cc @@ -259,10 +259,10 @@ class SignalsTest : public Multiprocess { bool (*install_handlers)(Signals::Handler, int, Signals::OldActions*); if (Signals::IsCrashSignal(sig_)) { install_handlers = [](Signals::Handler handler, - int sig, + int flags, Signals::OldActions* old_actions) { return Signals::InstallCrashHandlers( - handler, sig, old_actions, nullptr); + handler, flags, old_actions, nullptr); }; } else if (Signals::IsTerminateSignal(sig_)) { install_handlers = Signals::InstallTerminateHandlers; From a8d66ae7839a59d104b35ec6eb31f95cddd1813c Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 7 Nov 2019 19:49:23 -0800 Subject: [PATCH 286/401] linux: don't set ptracer if yama doesn't exist Change-Id: I0f2c1a1eef93151014c3f715a64ba99b63358887 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1904957 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- client/crashpad_client_linux.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 01883243..2adcefca 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -27,6 +27,7 @@ #include "client/client_argv_handling.h" #include "third_party/lss/lss.h" #include "util/file/file_io.h" +#include "util/file/filesystem.h" #include "util/linux/exception_handler_client.h" #include "util/linux/exception_information.h" #include "util/linux/scoped_pr_set_dumpable.h" @@ -380,9 +381,14 @@ bool CrashpadClient::StartHandler( return false; } + pid_t handler_pid = -1; + if (!IsRegularFile(base::FilePath("/proc/sys/kernel/yama/ptrace_scope"))) { + handler_pid = 0; + } + auto signal_handler = RequestCrashDumpHandler::Get(); return signal_handler->Initialize( - std::move(client_sock), -1, &unhandled_signals_); + std::move(client_sock), handler_pid, &unhandled_signals_); } #if defined(OS_ANDROID) || defined(OS_LINUX) From 0208c1a175e12480698f3befcabf604f45812b20 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Tue, 12 Nov 2019 12:08:54 -0800 Subject: [PATCH 287/401] fuchsia: Don't capture incorrect/unreasonably large stacks In a stack overflow test from the Fuchsia tree, an intentional crash was being induced that at the point it was reported to Crashpad resulted in a stack pointer outside of the stack. This caused two problems: - Crashpad attempted to capture that whole "thing" which could have been anything, and in the failing test was a 1G guard region - The whole wrong thing could be very large, resulting in OOM when trying to write the minidump, which was the symptom of the bug. Don't attempt to continue of SP isn't at least in a mapping, and don't capture too-large regions for the stack as nothing useful can come of that anyway. New test added: ProcessSnapshotFuchsiaTest.InvalidStackPointer. Bug: fuchsia:41212 Change-Id: Ifb48fd8b4b5b2f0cf10ab97e01dbd8b842368775 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1912942 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Francois Rousseau <frousseau@google.com> --- snapshot/fuchsia/process_reader_fuchsia.cc | 14 ++- .../fuchsia/process_snapshot_fuchsia_test.cc | 91 +++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/snapshot/fuchsia/process_reader_fuchsia.cc b/snapshot/fuchsia/process_reader_fuchsia.cc index c76a1f57..4522e511 100644 --- a/snapshot/fuchsia/process_reader_fuchsia.cc +++ b/snapshot/fuchsia/process_reader_fuchsia.cc @@ -53,7 +53,9 @@ void GetStackRegions( } if (range_with_sp.type != ZX_INFO_MAPS_TYPE_MAPPING) { - LOG(ERROR) << "stack range has unexpected type, continuing anyway"; + LOG(ERROR) << "stack range has unexpected type " << range_with_sp.type + << ", aborting"; + return; } if (range_with_sp.u.mapping.mmu_flags & ZX_VM_PERM_EXECUTE) { @@ -75,8 +77,16 @@ void GetStackRegions( range_with_sp.base); const size_t region_size = range_with_sp.size - (start_address - range_with_sp.base); + + // Because most Fuchsia processes use safestack, it is very unlikely that a + // stack this large would be valid. Even if it were, avoid creating + // unreasonably large dumps by artificially limiting the captured amount. + constexpr uint64_t kMaxStackCapture = 1048576u; + LOG_IF(ERROR, region_size > kMaxStackCapture) + << "clamping unexpectedly large stack capture of " << region_size; + const size_t clamped_region_size = std::min(region_size, kMaxStackCapture); stack_regions->push_back( - CheckedRange<zx_vaddr_t, size_t>(start_address, region_size)); + CheckedRange<zx_vaddr_t, size_t>(start_address, clamped_region_size)); // TODO(scottmg): https://crashpad.chromium.org/bug/196, once the retrievable // registers include FS and similar for ARM, retrieve the region for the diff --git a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc index 52215a78..e1b83ac6 100644 --- a/snapshot/fuchsia/process_snapshot_fuchsia_test.cc +++ b/snapshot/fuchsia/process_snapshot_fuchsia_test.cc @@ -24,6 +24,7 @@ #include "gtest/gtest.h" #include "snapshot/fuchsia/process_snapshot_fuchsia.h" #include "test/multiprocess_exec.h" +#include "util/fuchsia/koid_utilities.h" #include "util/fuchsia/scoped_task_suspend.h" namespace crashpad { @@ -139,6 +140,96 @@ TEST(ProcessSnapshotFuchsiaTest, AddressSpaceMapping) { test.Run(); } +CRASHPAD_CHILD_TEST_MAIN(StackPointerIntoInvalidLocation) { + // Map a large block, output the base address of it, and block. The parent + // will artificially set the SP into this large block to confirm that a huge + // stack is not accidentally captured. + zx_handle_t large_vmo; + constexpr uint64_t kSize = 1 << 30u; + zx_status_t status = zx_vmo_create(kSize, 0, &large_vmo); + ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create"; + zx_vaddr_t mapped_addr; + status = zx_vmar_map(zx_vmar_root_self(), + ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, + 0, + large_vmo, + 0, + kSize, + &mapped_addr); + ZX_CHECK(status == ZX_OK, status) << "zx_vmar_map"; + CheckedWriteFile(StdioFileHandle(StdioStream::kStandardOutput), + &mapped_addr, + sizeof(mapped_addr)); + zx_nanosleep(ZX_TIME_INFINITE); + return 0; +} + +class InvalidStackPointerTest : public MultiprocessExec { + public: + InvalidStackPointerTest() : MultiprocessExec() { + SetChildTestMainFunction("StackPointerIntoInvalidLocation"); + SetExpectedChildTermination(kTerminationNormal, + ZX_TASK_RETCODE_SYSCALL_KILL); + } + ~InvalidStackPointerTest() {} + + private: + void MultiprocessParent() override { + uint64_t address_of_large_mapping; + ASSERT_TRUE(ReadFileExactly(ReadPipeHandle(), + &address_of_large_mapping, + sizeof(address_of_large_mapping))); + + ScopedTaskSuspend suspend(*ChildProcess()); + + std::vector<zx::thread> threads = GetThreadHandles(*ChildProcess()); + ASSERT_EQ(threads.size(), 1u); + + zx_thread_state_general_regs_t regs; + ASSERT_EQ(threads[0].read_state( + ZX_THREAD_STATE_GENERAL_REGS, ®s, sizeof(regs)), + ZX_OK); + + constexpr uint64_t kOffsetIntoMapping = 1024; +#if defined(ARCH_CPU_X86_64) + regs.rsp = address_of_large_mapping + kOffsetIntoMapping; +#elif defined(ARCH_CPU_ARM64) + regs.sp = address_of_large_mapping + kOffsetIntoMapping; +#else +#error +#endif + + ASSERT_EQ(threads[0].write_state( + ZX_THREAD_STATE_GENERAL_REGS, ®s, sizeof(regs)), + ZX_OK); + + ProcessSnapshotFuchsia process_snapshot; + ASSERT_TRUE(process_snapshot.Initialize(*ChildProcess())); + + ASSERT_EQ(process_snapshot.Threads().size(), 1u); + const MemorySnapshot* stack = process_snapshot.Threads()[0]->Stack(); + ASSERT_TRUE(stack); + // Ensure the stack capture isn't unreasonably large. + EXPECT_LT(stack->Size(), 10 * 1048576u); + + // As we've corrupted the child, don't let it run again. + ASSERT_EQ(ChildProcess()->kill(), ZX_OK); + } + + DISALLOW_COPY_AND_ASSIGN(InvalidStackPointerTest); +}; + +// This is a test for a specific failure detailed in +// https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=41212. A test of stack +// behavior that was intentionally overflowing the stack, and so when Crashpad +// received the exception the SP did not point into the actual stack. This +// caused Crashpad to erronously capture the "stack" from the next mapping in +// the address space (which could be very large, cause OOM, etc.). +TEST(ProcessSnapshotFuchsiaTest, InvalidStackPointer) { + InvalidStackPointerTest test; + test.Run(); +} + } // namespace } // namespace test } // namespace crashpad From 2291bfa32ef1136a3654e680279892af33f6b07e Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 13 Nov 2019 12:44:29 -0800 Subject: [PATCH 288/401] android, gyp: fix the build Change-Id: If852448b5719310b73774cac635ef9c52a3efc22 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1914349 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/util.gyp | 1 + 1 file changed, 1 insertion(+) diff --git a/util/util.gyp b/util/util.gyp index 82ba3938..91c0310f 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -416,6 +416,7 @@ ['include', '^linux/'], ['include', '^misc/capture_context_linux\\.S$'], ['include', '^misc/paths_linux\\.cc$'], + ['include', '^misc/time_linux\\.cc$'], ['include', '^posix/process_info_linux\\.cc$'], ['include', '^process/process_memory_linux\\.cc$'], ['include', '^process/process_memory_linux\\.h$'], From 74490f00a47bbe38b08354eb9286f616285e8d22 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 13 Nov 2019 13:39:23 -0800 Subject: [PATCH 289/401] linux: roll lss and use sys_sigtimedwait/sys_sigprocmask Bug: crashpad:265 Change-Id: I4b8f566e2a211cca96eef8a2c1098408a38bcf23 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1914840 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- DEPS | 2 +- .../linux/exception_handler_server_test.cc | 9 ------- util/linux/exception_handler_client.cc | 27 ++++++++----------- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/DEPS b/DEPS index 4cf88253..9b50aa55 100644 --- a/DEPS +++ b/DEPS @@ -30,7 +30,7 @@ deps = { '8bee09f4a57807136593ddc906b0b213c21f9014', 'crashpad/third_party/lss/lss': Var('chromium_git') + '/linux-syscall-support.git@' + - '8048ece6c16c91acfe0d36d1d3cc0890ab6e945c', + '726d71ec08d15493b94eff456bc31faecf0a5902', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + 'cdab1e6263ec7f3f61763efc1dac863f8dc07c80', diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index 45f19965..7da5babe 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -367,16 +367,7 @@ TEST_P(ExceptionHandlerServerTest, RequestCrashDumpError) { INSTANTIATE_TEST_SUITE_P(ExceptionHandlerServerTestSuite, ExceptionHandlerServerTest, -#if defined(OS_ANDROID) && __ANDROID_API__ < 23 - // TODO(jperaza): Using a multi-client socket is not - // supported on Android until an lss sigtimedwait() - // wrapper is available to use in - // ExceptionHandlerClient::SignalCrashDump(). - // https://crbug.com/crashpad/265 - testing::Values(false) -#else testing::Bool() -#endif ); } // namespace diff --git a/util/linux/exception_handler_client.cc b/util/linux/exception_handler_client.cc index 64ae0067..98edb306 100644 --- a/util/linux/exception_handler_client.cc +++ b/util/linux/exception_handler_client.cc @@ -23,6 +23,7 @@ #include "base/logging.h" #include "base/posix/eintr_wrapper.h" #include "build/build_config.h" +#include "third_party/lss/lss.h" #include "util/file/file_io.h" #include "util/linux/ptrace_broker.h" #include "util/linux/socket.h" @@ -39,20 +40,21 @@ namespace { class ScopedSigprocmaskRestore { public: - explicit ScopedSigprocmaskRestore(const sigset_t& set_to_block) + explicit ScopedSigprocmaskRestore(const kernel_sigset_t& set_to_block) : orig_mask_(), mask_is_set_(false) { - mask_is_set_ = sigprocmask(SIG_BLOCK, &set_to_block, &orig_mask_) == 0; + mask_is_set_ = sys_sigprocmask(SIG_BLOCK, &set_to_block, &orig_mask_) == 0; DPLOG_IF(ERROR, !mask_is_set_) << "sigprocmask"; } ~ScopedSigprocmaskRestore() { - if (mask_is_set_ && sigprocmask(SIG_SETMASK, &orig_mask_, nullptr) != 0) { + if (mask_is_set_ && + sys_sigprocmask(SIG_SETMASK, &orig_mask_, nullptr) != 0) { DPLOG(ERROR) << "sigprocmask"; } } private: - sigset_t orig_mask_; + kernel_sigset_t orig_mask_; bool mask_is_set_; DISALLOW_COPY_AND_ASSIGN(ScopedSigprocmaskRestore); @@ -119,11 +121,9 @@ void ExceptionHandlerClient::SetCanSetPtracer(bool can_set_ptracer) { int ExceptionHandlerClient::SignalCrashDump( const ExceptionHandlerProtocol::ClientInformation& info, VMAddress stack_pointer) { - // TODO(jperaza): Use lss for system calls when sys_sigtimedwait() exists. - // https://crbug.com/crashpad/265 - sigset_t dump_done_sigset; - sigemptyset(&dump_done_sigset); - sigaddset(&dump_done_sigset, ExceptionHandlerProtocol::kDumpDoneSignal); + kernel_sigset_t dump_done_sigset; + sys_sigemptyset(&dump_done_sigset); + sys_sigaddset(&dump_done_sigset, ExceptionHandlerProtocol::kDumpDoneSignal); ScopedSigprocmaskRestore scoped_block(dump_done_sigset); int status = SendCrashDumpRequest(info, stack_pointer); @@ -131,19 +131,14 @@ int ExceptionHandlerClient::SignalCrashDump( return status; } -#if defined(OS_ANDROID) && __ANDROID_API__ < 23 - // sigtimedwait() wrappers aren't available on Android until API 23 but this - // can use the lss wrapper when it's available. - NOTREACHED(); -#else siginfo_t siginfo = {}; timespec timeout; timeout.tv_sec = 5; timeout.tv_nsec = 0; - if (HANDLE_EINTR(sigtimedwait(&dump_done_sigset, &siginfo, &timeout)) < 0) { + if (HANDLE_EINTR(sys_sigtimedwait(&dump_done_sigset, &siginfo, &timeout)) < + 0) { return errno; } -#endif return 0; } From 7fd5226a97ea9161382384b1fa6c6b329933ad27 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 27 Nov 2019 11:49:15 -0800 Subject: [PATCH 290/401] Give database settings kOwnerOnly permissions Bug: b/145240822 Change-Id: Id3720471ce67edd981c35b62cf1d8f810899646c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1940848 Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/settings.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/settings.cc b/client/settings.cc index f6db78db..db9dface 100644 --- a/client/settings.cc +++ b/client/settings.cc @@ -226,10 +226,10 @@ Settings::ScopedLockedFileHandle Settings::OpenForReadingAndWriting( FileHandle handle; if (log_open_error) { handle = LoggingOpenFileForReadAndWrite( - file_path(), mode, FilePermissions::kWorldReadable); + file_path(), mode, FilePermissions::kOwnerOnly); } else { handle = OpenFileForReadAndWrite( - file_path(), mode, FilePermissions::kWorldReadable); + file_path(), mode, FilePermissions::kOwnerOnly); } return MakeScopedLockedFileHandle( From 359fc4a1336db10c8c9aae86f495ae415289b5b1 Mon Sep 17 00:00:00 2001 From: James Forshaw <forshaw@chromium.org> Date: Tue, 3 Dec 2019 10:20:34 -0800 Subject: [PATCH 291/401] [Windows] Add checks for DLL loader lock. This CL adds code to check if the current thread holds the DLL loader lock. This code can be used to enforce the requirement that certain parts of crashpad, such as process creation are not done during calls to DllMain which can lead to deadlocks and crashes. Only one check is current enforced, in client process creation, and only in debug builds. Bug: crashpad: 316 Change-Id: I5757a264bbf28ce2ab88a0cd7ac9481e46428c17 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1945993 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: James Forshaw <forshaw@chromium.org> --- client/crashpad_client_win.cc | 3 ++ util/BUILD.gn | 14 +++++++++ util/win/loader_lock.cc | 52 ++++++++++++++++++++++++++++++++ util/win/loader_lock.h | 25 +++++++++++++++ util/win/loader_lock_test.cc | 36 ++++++++++++++++++++++ util/win/loader_lock_test_dll.cc | 41 +++++++++++++++++++++++++ 6 files changed, 171 insertions(+) create mode 100644 util/win/loader_lock.cc create mode 100644 util/win/loader_lock.h create mode 100644 util/win/loader_lock_test.cc create mode 100644 util/win/loader_lock_test_dll.cc diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc index c1c3ff14..4963f24f 100644 --- a/client/crashpad_client_win.cc +++ b/client/crashpad_client_win.cc @@ -41,6 +41,7 @@ #include "util/win/get_function.h" #include "util/win/handle.h" #include "util/win/initial_client_data.h" +#include "util/win/loader_lock.h" #include "util/win/nt_internals.h" #include "util/win/ntstatus_logging.h" #include "util/win/process_info.h" @@ -346,6 +347,8 @@ class ScopedCallSetHandlerStartupState { bool StartHandlerProcess( std::unique_ptr<BackgroundHandlerStartThreadData> data) { + CHECK(!IsThreadInLoaderLock()); + ScopedCallSetHandlerStartupState scoped_startup_state_caller; std::wstring command_line; diff --git a/util/BUILD.gn b/util/BUILD.gn index 02558909..fcf559be 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -371,6 +371,8 @@ static_library("util") { "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", @@ -666,6 +668,7 @@ source_set("util_test") { "win/get_function_test.cc", "win/handle_test.cc", "win/initial_client_data_test.cc", + "win/loader_lock_test.cc", "win/process_info_test.cc", "win/registration_protocol_win_test.cc", "win/safe_terminate_process_test.cc", @@ -718,6 +721,7 @@ source_set("util_test") { "dbghelp.lib", ] data_deps += [ + ":crashpad_util_test_loader_lock_test", ":crashpad_util_test_process_info_test_child", ":crashpad_util_test_safe_terminate_process_test_child", ] @@ -738,4 +742,14 @@ if (crashpad_is_win) { "win/safe_terminate_process_test_child.cc", ] } + + crashpad_loadable_module("crashpad_util_test_loader_lock_test") { + testonly = true + sources = [ + "win/loader_lock_test_dll.cc", + ] + deps = [ + ":util", + ] + } } diff --git a/util/win/loader_lock.cc b/util/win/loader_lock.cc new file mode 100644 index 00000000..0c9a3cc5 --- /dev/null +++ b/util/win/loader_lock.cc @@ -0,0 +1,52 @@ +// 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. + +#include "util/win/loader_lock.h" + +#include <windows.h> + +#include "build/build_config.h" +#include "util/win/process_structs.h" + +namespace crashpad { + +namespace { + +#ifdef ARCH_CPU_64_BITS +using NativeTraits = process_types::internal::Traits64; +#else +using NativeTraits = process_types::internal::Traits32; +#endif // ARCH_CPU_64_BITS + +using PEB = process_types::PEB<NativeTraits>; +using TEB = process_types::TEB<NativeTraits>; +using RTL_CRITICAL_SECTION = process_types::RTL_CRITICAL_SECTION<NativeTraits>; + +TEB* GetTeb() { + return reinterpret_cast<TEB*>(NtCurrentTeb()); +} + +PEB* GetPeb() { + return reinterpret_cast<PEB*>(GetTeb()->ProcessEnvironmentBlock); +} + +} // namespace + +bool IsThreadInLoaderLock() { + RTL_CRITICAL_SECTION* loader_lock = + reinterpret_cast<RTL_CRITICAL_SECTION*>(GetPeb()->LoaderLock); + return loader_lock->OwningThread == GetTeb()->ClientId.UniqueThread; +} + +} // namespace crashpad diff --git a/util/win/loader_lock.h b/util/win/loader_lock.h new file mode 100644 index 00000000..3ee34bb4 --- /dev/null +++ b/util/win/loader_lock.h @@ -0,0 +1,25 @@ +// 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_UTIL_WIN_LOADER_LOCK_H_ +#define CRASHPAD_UTIL_WIN_LOADER_LOCK_H_ + +namespace crashpad { + +//! \return `true` if the current thread holds the loader lock. +bool IsThreadInLoaderLock(); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_WIN_LOADER_LOCK_H_ diff --git a/util/win/loader_lock_test.cc b/util/win/loader_lock_test.cc new file mode 100644 index 00000000..9fa32f87 --- /dev/null +++ b/util/win/loader_lock_test.cc @@ -0,0 +1,36 @@ +// 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. + +#include "util/win/loader_lock.h" + +#include "gtest/gtest.h" +#include "util/win/get_function.h" + +extern "C" bool LoaderLockDetected(); + +namespace crashpad { +namespace test { +namespace { + +TEST(LoaderLock, Detected) { + EXPECT_FALSE(IsThreadInLoaderLock()); + auto* loader_lock_detected = GET_FUNCTION_REQUIRED( + L"crashpad_util_test_loader_lock_test.dll", LoaderLockDetected); + EXPECT_TRUE(loader_lock_detected()); + EXPECT_FALSE(IsThreadInLoaderLock()); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/win/loader_lock_test_dll.cc b/util/win/loader_lock_test_dll.cc new file mode 100644 index 00000000..fd1bfe03 --- /dev/null +++ b/util/win/loader_lock_test_dll.cc @@ -0,0 +1,41 @@ +// 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. + +#include <windows.h> + +#include "util/win/loader_lock.h" + +namespace { + +bool g_loader_lock_detected = false; + +} // namespace + +extern "C" { + +__declspec(dllexport) bool LoaderLockDetected() { + return g_loader_lock_detected; +} + +} // extern "C" + +BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) { + switch (reason) { + case DLL_PROCESS_ATTACH: + g_loader_lock_detected = crashpad::IsThreadInLoaderLock(); + break; + } + + return TRUE; +} From 9a312ddff5fad67e5d0bce6315a614b47280aa2e Mon Sep 17 00:00:00 2001 From: Vitaly Buka <vitalybuka@chromium.org> Date: Tue, 3 Dec 2019 18:21:55 -0800 Subject: [PATCH 292/401] Increase kAllowedOffset for non-optimized build "init_stack_vars = true" inserts additional instructions which usually removed by optimization if code does not rely on undefined behaviour of uninitialized variables. However in non-optimized build these instructions may still be present. Bug: chromium:1030261 Change-Id: I85d1d0a240dcd1c29c6ff148e88d572b5dcc81d1 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1949846 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vitaly Buka <vitalybuka@chromium.org> --- snapshot/win/exception_snapshot_win_test.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index b4c44a83..5a0535b5 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -213,6 +213,9 @@ class SimulateDelegate : public ExceptionHandlerServer::Delegate { // ASan instrumentation inserts more instructions between the expected // location and what's reported. https://crbug.com/845011. constexpr uint64_t kAllowedOffset = 500; +#elif !NDEBUG + // Debug build is likely not optimized and contains more instructions. + constexpr uint64_t kAllowedOffset = 150; #else constexpr uint64_t kAllowedOffset = 100; #endif From e01fb92aa9a950dd875e65620f53ce3b15e2d23b Mon Sep 17 00:00:00 2001 From: Vitaly Buka <vitalybuka@chromium.org> Date: Wed, 4 Dec 2019 13:32:09 -0800 Subject: [PATCH 293/401] Fix #elif in crrev.com/c/1949846 I was editing the patch in gerrit and looks like it undone !defined change and I landed wrong version. Bug: chromium:1030261 Change-Id: Ib645839bac5450fe55ecd9f3a38155022b7f6c13 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1951624 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vitaly Buka <vitalybuka@chromium.org> --- snapshot/win/exception_snapshot_win_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index 5a0535b5..2d4e9090 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -213,7 +213,7 @@ class SimulateDelegate : public ExceptionHandlerServer::Delegate { // ASan instrumentation inserts more instructions between the expected // location and what's reported. https://crbug.com/845011. constexpr uint64_t kAllowedOffset = 500; -#elif !NDEBUG +#elif !defined(NDEBUG) // Debug build is likely not optimized and contains more instructions. constexpr uint64_t kAllowedOffset = 150; #else From 6b81e8173fa385172d5a91307114321c2ad1544b Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Thu, 5 Dec 2019 07:49:11 -0800 Subject: [PATCH 294/401] Removes the obsolete cq.cfg file. The authoritative version of this config now lives in "commit-queue.cfg" on the origin/infra/config branch. This config was migrated in: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1436767 BUG=916292 Change-Id: Ie49028d043775e789fb948b24485c45d168720c3 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1953363 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- infra/config/cq.cfg | 51 --------------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 infra/config/cq.cfg diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg deleted file mode 100644 index c0522b47..00000000 --- a/infra/config/cq.cfg +++ /dev/null @@ -1,51 +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. - -# See https://luci-config.appspot.com/schemas/projects/refs:cq.cfg for the -# documentation of this file format. - -version: 1 -cq_status_url: "https://chromium-cq-status.appspot.com" - -# This is required for gerrit projects. -git_repo_url: "https://chromium.googlesource.com/crashpad/crashpad" - -# Crashpad uses gerrit with no special options. -gerrit {} - -verifiers { - gerrit_cq_ability { - committer_list: "project-crashpad-tryjob-access" - dry_run_access_list: "project-crashpad-tryjob-access" - } - try_job { - buckets { - name: "luci.crashpad.try" - builders { name: "crashpad_try_mac_dbg" } - builders { name: "crashpad_try_mac_rel" } - builders { name: "crashpad_try_win_dbg" } - builders { name: "crashpad_try_win_rel" } - builders { name: "crashpad_try_linux_dbg" } - builders { name: "crashpad_try_linux_rel" } - builders { name: "crashpad_try_fuchsia_arm64_dbg" } - builders { name: "crashpad_try_fuchsia_arm64_rel" } - builders { name: "crashpad_try_fuchsia_x64_dbg" } - builders { name: "crashpad_try_fuchsia_x64_rel" } - # https://crbug.com/743139 - disabled until we can move these to swarming, - # at which point we can just remove them. - #builders { name: "crashpad_try_win_x86_dbg" } - #builders { name: "crashpad_try_win_x86_rel" } - } - } -} From c9f089eee409d878b22729719a43124c2fa19a27 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 5 Dec 2019 12:01:58 -0800 Subject: [PATCH 295/401] linux: update lss Change-Id: Icb893e5fad1e94da5f401cb56d882baec8620c0b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1954243 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 9b50aa55..7b5d60b2 100644 --- a/DEPS +++ b/DEPS @@ -30,7 +30,7 @@ deps = { '8bee09f4a57807136593ddc906b0b213c21f9014', 'crashpad/third_party/lss/lss': Var('chromium_git') + '/linux-syscall-support.git@' + - '726d71ec08d15493b94eff456bc31faecf0a5902', + '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + 'cdab1e6263ec7f3f61763efc1dac863f8dc07c80', From bcab7ad54c2ed7df41f22de117657c1ade308434 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 5 Dec 2019 12:36:26 -0800 Subject: [PATCH 296/401] linux: handle large mapped files Chrome on Android normally builds the handler without large file support because support for large files varies by API level and NDK version. https://cs.chromium.org/chromium/src/build/config/compiler/BUILD.gn?rcl=6b5017edcd8544acbdb157086a1645ce36c03057&l=360 https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md#32_bit-and The handler still needs to able to handle large files mapped by other code modules. Bug: crashpad:312 Change-Id: I1022b706797f41445650f82c425a92e6e2308618 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1954426 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/linux/memory_map.cc | 28 ++-------------------------- util/linux/memory_map.h | 2 +- util/linux/memory_map_test.cc | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/util/linux/memory_map.cc b/util/linux/memory_map.cc index 17fd7a3d..0890cd61 100644 --- a/util/linux/memory_map.cc +++ b/util/linux/memory_map.cc @@ -31,33 +31,9 @@ namespace crashpad { namespace { -// This function is used in this file specfically for signed or unsigned longs. -// longs are typically either int or int64 sized, but pointers to longs are not -// automatically coerced to pointers to ints when they are the same size. -// Simply adding a StringToNumber for longs doesn't work since sometimes long -// and int64_t are actually the same type, resulting in a redefinition error. -template <typename Type> -bool LocalStringToNumber(const std::string& string, Type* number) { - static_assert(sizeof(Type) == sizeof(int) || sizeof(Type) == sizeof(int64_t), - "Unexpected Type size"); - - char data[sizeof(Type)]; - if (sizeof(Type) == sizeof(int)) { - if (!StringToNumber(string, reinterpret_cast<unsigned int*>(data))) { - return false; - } - } else { - if (!StringToNumber(string, reinterpret_cast<uint64_t*>(data))) { - return false; - } - } - *number = bit_cast<Type>(data); - return true; -} - template <typename Type> bool HexStringToNumber(const std::string& string, Type* number) { - return LocalStringToNumber("0x" + string, number); + return StringToNumber("0x" + string, number); } // The result from parsing a line from the maps file. @@ -182,7 +158,7 @@ ParseResult ParseMapsLine(DelimitedFileReader* maps_file_reader, if (maps_file_reader->GetDelim(' ', &field) != DelimitedFileReader::Result::kSuccess || - (field.pop_back(), !LocalStringToNumber(field, &mapping.inode))) { + (field.pop_back(), !StringToNumber(field, &mapping.inode))) { LOG(ERROR) << "format error"; return ParseResult::kError; } diff --git a/util/linux/memory_map.h b/util/linux/memory_map.h index a062b560..d43b7af4 100644 --- a/util/linux/memory_map.h +++ b/util/linux/memory_map.h @@ -43,7 +43,7 @@ class MemoryMap { std::string name; CheckedLinuxAddressRange range; - off_t offset; + off64_t offset; dev_t device; ino_t inode; bool readable; diff --git a/util/linux/memory_map_test.cc b/util/linux/memory_map_test.cc index 2df44b3a..20e5f227 100644 --- a/util/linux/memory_map_test.cc +++ b/util/linux/memory_map_test.cc @@ -29,7 +29,9 @@ #include "test/linux/fake_ptrace_connection.h" #include "test/multiprocess.h" #include "test/scoped_temp_dir.h" +#include "third_party/lss/lss.h" #include "util/file/file_io.h" +#include "util/file/scoped_remove_file.h" #include "util/linux/direct_ptrace_connection.h" #include "util/misc/clock.h" #include "util/misc/from_pointer_cast.h" @@ -39,6 +41,38 @@ namespace crashpad { namespace test { namespace { +TEST(MemoryMap, SelfLargeFiles) { + // This test is meant to test the handler's ability to understand files + // mapped from large offsets, even if the handler wasn't built with + // _FILE_OFFSET_BITS=64. ScopedTempDir needs to stat files to determine + // whether to recurse into directories, which may will fail without large file + // support. ScopedRemoveFile doesn't have that restriction. + ScopedTempDir dir; + ScopedRemoveFile large_file_path(dir.path().Append("crashpad_test_file")); + ScopedFileHandle handle( + LoggingOpenFileForReadAndWrite(large_file_path.get(), + FileWriteMode::kCreateOrFail, + FilePermissions::kWorldReadable)); + ASSERT_TRUE(handle.is_valid()); + + // sys_fallocate supports large files as long as the kernel supports them, + // regardless of _FILE_OFFSET_BITS. + off64_t off = 1llu + UINT32_MAX; + ASSERT_EQ(sys_fallocate(handle.get(), 0, off, getpagesize()), 0) + << ErrnoMessage("fallocate"); + + ScopedMmap mapping; + void* addr = sys_mmap( + nullptr, getpagesize(), PROT_READ, MAP_SHARED, handle.get(), off); + ASSERT_TRUE(addr); + ASSERT_TRUE(mapping.ResetAddrLen(addr, getpagesize())); + + FakePtraceConnection connection; + ASSERT_TRUE(connection.Initialize(getpid())); + MemoryMap map; + ASSERT_TRUE(map.Initialize(&connection)); +} + TEST(MemoryMap, SelfBasic) { ScopedMmap mmapping; ASSERT_TRUE(mmapping.ResetMmap(nullptr, From 31470459b624f440744c2f8830f05e19a99a0325 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Thu, 5 Dec 2019 22:59:50 -0500 Subject: [PATCH 297/401] Fix line endings on files introduced in 359fc4a1336d "\r\n" was used instead of "\n" on four new files. No other "\r" appears in any text file, repository-wide. Bug: crashpad:316 Change-Id: I94f5d20cd2498e76efdee6062382669362e6e53d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1954713 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/win/loader_lock.cc | 104 +++++++++++++++---------------- util/win/loader_lock.h | 50 +++++++-------- util/win/loader_lock_test.cc | 72 ++++++++++----------- util/win/loader_lock_test_dll.cc | 82 ++++++++++++------------ 4 files changed, 154 insertions(+), 154 deletions(-) diff --git a/util/win/loader_lock.cc b/util/win/loader_lock.cc index 0c9a3cc5..187ef84e 100644 --- a/util/win/loader_lock.cc +++ b/util/win/loader_lock.cc @@ -1,52 +1,52 @@ -// 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. - -#include "util/win/loader_lock.h" - -#include <windows.h> - -#include "build/build_config.h" -#include "util/win/process_structs.h" - -namespace crashpad { - -namespace { - -#ifdef ARCH_CPU_64_BITS -using NativeTraits = process_types::internal::Traits64; -#else -using NativeTraits = process_types::internal::Traits32; -#endif // ARCH_CPU_64_BITS - -using PEB = process_types::PEB<NativeTraits>; -using TEB = process_types::TEB<NativeTraits>; -using RTL_CRITICAL_SECTION = process_types::RTL_CRITICAL_SECTION<NativeTraits>; - -TEB* GetTeb() { - return reinterpret_cast<TEB*>(NtCurrentTeb()); -} - -PEB* GetPeb() { - return reinterpret_cast<PEB*>(GetTeb()->ProcessEnvironmentBlock); -} - -} // namespace - -bool IsThreadInLoaderLock() { - RTL_CRITICAL_SECTION* loader_lock = - reinterpret_cast<RTL_CRITICAL_SECTION*>(GetPeb()->LoaderLock); - return loader_lock->OwningThread == GetTeb()->ClientId.UniqueThread; -} - -} // namespace crashpad +// 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. + +#include "util/win/loader_lock.h" + +#include <windows.h> + +#include "build/build_config.h" +#include "util/win/process_structs.h" + +namespace crashpad { + +namespace { + +#ifdef ARCH_CPU_64_BITS +using NativeTraits = process_types::internal::Traits64; +#else +using NativeTraits = process_types::internal::Traits32; +#endif // ARCH_CPU_64_BITS + +using PEB = process_types::PEB<NativeTraits>; +using TEB = process_types::TEB<NativeTraits>; +using RTL_CRITICAL_SECTION = process_types::RTL_CRITICAL_SECTION<NativeTraits>; + +TEB* GetTeb() { + return reinterpret_cast<TEB*>(NtCurrentTeb()); +} + +PEB* GetPeb() { + return reinterpret_cast<PEB*>(GetTeb()->ProcessEnvironmentBlock); +} + +} // namespace + +bool IsThreadInLoaderLock() { + RTL_CRITICAL_SECTION* loader_lock = + reinterpret_cast<RTL_CRITICAL_SECTION*>(GetPeb()->LoaderLock); + return loader_lock->OwningThread == GetTeb()->ClientId.UniqueThread; +} + +} // namespace crashpad diff --git a/util/win/loader_lock.h b/util/win/loader_lock.h index 3ee34bb4..6c6b311f 100644 --- a/util/win/loader_lock.h +++ b/util/win/loader_lock.h @@ -1,25 +1,25 @@ -// 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_UTIL_WIN_LOADER_LOCK_H_ -#define CRASHPAD_UTIL_WIN_LOADER_LOCK_H_ - -namespace crashpad { - -//! \return `true` if the current thread holds the loader lock. -bool IsThreadInLoaderLock(); - -} // namespace crashpad - -#endif // CRASHPAD_UTIL_WIN_LOADER_LOCK_H_ +// 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_UTIL_WIN_LOADER_LOCK_H_ +#define CRASHPAD_UTIL_WIN_LOADER_LOCK_H_ + +namespace crashpad { + +//! \return `true` if the current thread holds the loader lock. +bool IsThreadInLoaderLock(); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_WIN_LOADER_LOCK_H_ diff --git a/util/win/loader_lock_test.cc b/util/win/loader_lock_test.cc index 9fa32f87..d33ea5ac 100644 --- a/util/win/loader_lock_test.cc +++ b/util/win/loader_lock_test.cc @@ -1,36 +1,36 @@ -// 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. - -#include "util/win/loader_lock.h" - -#include "gtest/gtest.h" -#include "util/win/get_function.h" - -extern "C" bool LoaderLockDetected(); - -namespace crashpad { -namespace test { -namespace { - -TEST(LoaderLock, Detected) { - EXPECT_FALSE(IsThreadInLoaderLock()); - auto* loader_lock_detected = GET_FUNCTION_REQUIRED( - L"crashpad_util_test_loader_lock_test.dll", LoaderLockDetected); - EXPECT_TRUE(loader_lock_detected()); - EXPECT_FALSE(IsThreadInLoaderLock()); -} - -} // namespace -} // namespace test -} // namespace crashpad +// 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. + +#include "util/win/loader_lock.h" + +#include "gtest/gtest.h" +#include "util/win/get_function.h" + +extern "C" bool LoaderLockDetected(); + +namespace crashpad { +namespace test { +namespace { + +TEST(LoaderLock, Detected) { + EXPECT_FALSE(IsThreadInLoaderLock()); + auto* loader_lock_detected = GET_FUNCTION_REQUIRED( + L"crashpad_util_test_loader_lock_test.dll", LoaderLockDetected); + EXPECT_TRUE(loader_lock_detected()); + EXPECT_FALSE(IsThreadInLoaderLock()); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/win/loader_lock_test_dll.cc b/util/win/loader_lock_test_dll.cc index fd1bfe03..b673ab3d 100644 --- a/util/win/loader_lock_test_dll.cc +++ b/util/win/loader_lock_test_dll.cc @@ -1,41 +1,41 @@ -// 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. - -#include <windows.h> - -#include "util/win/loader_lock.h" - -namespace { - -bool g_loader_lock_detected = false; - -} // namespace - -extern "C" { - -__declspec(dllexport) bool LoaderLockDetected() { - return g_loader_lock_detected; -} - -} // extern "C" - -BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) { - switch (reason) { - case DLL_PROCESS_ATTACH: - g_loader_lock_detected = crashpad::IsThreadInLoaderLock(); - break; - } - - return TRUE; -} +// 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. + +#include <windows.h> + +#include "util/win/loader_lock.h" + +namespace { + +bool g_loader_lock_detected = false; + +} // namespace + +extern "C" { + +__declspec(dllexport) bool LoaderLockDetected() { + return g_loader_lock_detected; +} + +} // extern "C" + +BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) { + switch (reason) { + case DLL_PROCESS_ATTACH: + g_loader_lock_detected = crashpad::IsThreadInLoaderLock(); + break; + } + + return TRUE; +} From cba3dabf247ead4344acfd756bac235b6104430f Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 6 Dec 2019 13:31:55 -0500 Subject: [PATCH 298/401] =?UTF-8?q?Add=20.gitattributes,=20setting=20?= =?UTF-8?q?=E2=80=9Ctext=20eol=3Dlf=E2=80=9D=C2=A0or=20=E2=80=9Cbinary?= =?UTF-8?q?=E2=80=9D=C2=A0for=20all=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should prevent accidental "\r\n" line endings from being introduced again, as happened in 359fc4a1336d, fixed by 31470459b624. Also includes: Update mini_chromium to 0512d42698bfb47f2016ac627177c22d22b983d4 0512d42698bf Add .gitattributes, setting “text eol=lf” for all files Change-Id: Id84c014914fec66632006ed364e2b14b4f1c175c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1953807 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Robert Sesek <rsesek@chromium.org> --- .gitattributes | 59 +++++++++++++++++++ .gitignore | 14 +++++ DEPS | 2 +- handler/win/.gitattributes | 21 +++++++ .../.gitattributes | 17 ++++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 handler/win/.gitattributes create mode 100644 snapshot/elf/elf_image_reader_fuzzer_corpus/.gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..9bfc20d1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,59 @@ +# 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. + +*.S text eol=lf +*.asm text eol=lf +*.c text eol=lf +*.cc text eol=lf +*.cmx text eol=lf +*.css text eol=lf +*.defs text eol=lf +*.doxy text eol=lf +*.gn text eol=lf +*.gni text eol=lf +*.go text eol=lf +*.gyp text eol=lf +*.gypi text eol=lf +*.h text eol=lf +*.m text eol=lf +*.md text eol=lf +*.mm text eol=lf +*.pem text eol=lf +*.plist text eol=lf +*.proctype text eol=lf +*.py text eol=lf +*.sh text eol=lf +*.sym text eol=lf +*.txt text eol=lf +*.yaml text eol=lf +.clang-format text eol=lf +.gitattributes text eol=lf +.gitignore text eol=lf +.vpython text eol=lf +/AUTHORS text eol=lf +/CONTRIBUTORS text eol=lf +/LICENSE text eol=lf +/codereview.settings text eol=lf +APPLE_LICENSE text eol=lf +COPYING.LIB text eol=lf +DEPS text eol=lf +README text eol=lf +README.crashpad text eol=lf + +*.dat binary +*.dll binary +*.ico binary +*.obj binary +*.png binary +*.so binary diff --git a/.gitignore b/.gitignore index 90038f1d..eee931eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,17 @@ +# 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. + *.Makefile *.ninja *.pyc diff --git a/DEPS b/DEPS index 7b5d60b2..a20b19c0 100644 --- a/DEPS +++ b/DEPS @@ -33,7 +33,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'cdab1e6263ec7f3f61763efc1dac863f8dc07c80', + '0512d42698bfb47f2016ac627177c22d22b983d4', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/handler/win/.gitattributes b/handler/win/.gitattributes new file mode 100644 index 00000000..6495e512 --- /dev/null +++ b/handler/win/.gitattributes @@ -0,0 +1,21 @@ +# 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. + +# This should be a .cc file, which would allow its attributes to be controlled +# by the *.cc pattern in the root .gitattributes file, but it’s named with a +# .cpp extension instead. This file needs to be built with VC++6, a vintage 1998 +# compiler, which might not understand .cc to mean C++. Rather than setting +# attributes globally for .cpp files, which are undesirable (.cc should be used +# in its place), provide a file-specific mapping here. +/z7_test.cpp text eol=lf diff --git a/snapshot/elf/elf_image_reader_fuzzer_corpus/.gitattributes b/snapshot/elf/elf_image_reader_fuzzer_corpus/.gitattributes new file mode 100644 index 00000000..69463d13 --- /dev/null +++ b/snapshot/elf/elf_image_reader_fuzzer_corpus/.gitattributes @@ -0,0 +1,17 @@ +# 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. + +# ELF executables normally don’t have any extension, so there’s no pattern to +# match in the root .gitattributes file. +/ret42 binary From 3e4d6a9b7f39387a3dc2feac51094b1d9beba8e1 Mon Sep 17 00:00:00 2001 From: Tao Bai <michaelbai@chromium.org> Date: Fri, 6 Dec 2019 10:54:44 -0800 Subject: [PATCH 299/401] [log minidump] Base94OutputStream implementation Add Base94 encoding/decoding implementation and tests. Bug: crashpad:308 Change-Id: If3f25efcb277eacd5d8cbe1d66f22919872c7d64 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1796682 Commit-Queue: Tao Bai <michaelbai@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- util/BUILD.gn | 3 + util/stream/base94_output_stream.cc | 173 ++++++++++++++ util/stream/base94_output_stream.h | 79 ++++++ util/stream/base94_output_stream_test.cc | 290 +++++++++++++++++++++++ 4 files changed, 545 insertions(+) create mode 100644 util/stream/base94_output_stream.cc create mode 100644 util/stream/base94_output_stream.h create mode 100644 util/stream/base94_output_stream_test.cc diff --git a/util/BUILD.gn b/util/BUILD.gn index fcf559be..3317f7cc 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -166,6 +166,8 @@ static_library("util") { "stdlib/strnlen.cc", "stdlib/strnlen.h", "stdlib/thread_safe_vector.h", + "stream/base94_output_stream.cc", + "stream/base94_output_stream.h", "stream/output_stream_interface.h", "stream/zlib_output_stream.cc", "stream/zlib_output_stream.h", @@ -588,6 +590,7 @@ source_set("util_test") { "stdlib/strlcpy_test.cc", "stdlib/strnlen_test.cc", "stdlib/thread_safe_vector_test.cc", + "stream/base94_output_stream_test.cc", "stream/test_output_stream.cc", "stream/test_output_stream.h", "stream/zlib_output_stream_test.cc", diff --git a/util/stream/base94_output_stream.cc b/util/stream/base94_output_stream.cc new file mode 100644 index 00000000..a47d774b --- /dev/null +++ b/util/stream/base94_output_stream.cc @@ -0,0 +1,173 @@ +// 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. + +#include "util/stream/base94_output_stream.h" + +#include <algorithm> + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" + +namespace crashpad { + +namespace { +// To improve the space efficiency, we can encode 14 bits into two symbols +// if 14-bit number is less than 94^2 which is total number can be encoded +// by 2 digits of base94 number, in another word, if 13 bit number is +// smaller than 643, we could read one more bit, because even if the 14th +// bit is 1, the 14-bit number doesn’t exceed the max value. +constexpr uint16_t kMaxValueOf14BitEncoding = (94 * 94 - 1) & 0x1FFF; + +constexpr size_t kMaxBuffer = 4096; + +inline uint8_t EncodeByte(uint8_t byte) { + DCHECK(byte < 94); + return (byte >= 94u) ? 0xff : (byte + '!'); +} + +inline uint8_t DecodeByte(uint8_t byte) { + DCHECK(byte >= '!' && byte <= '~'); + return std::min(static_cast<uint8_t>(byte - '!'), static_cast<uint8_t>(94)); +} + +} // namespace + +Base94OutputStream::Base94OutputStream( + Mode mode, + std::unique_ptr<OutputStreamInterface> output_stream) + : mode_(mode), + output_stream_(std::move(output_stream)), + bit_buf_(0), + bit_count_(0), + symbol_buffer_(0), + flush_needed_(false), + flushed_(false) { + buffer_.reserve(kMaxBuffer); +} + +Base94OutputStream::~Base94OutputStream() { + DCHECK(!flush_needed_); +} + +bool Base94OutputStream::Write(const uint8_t* data, size_t size) { + DCHECK(!flushed_); + flush_needed_ = true; + return mode_ == Mode::kEncode ? Encode(data, size) : Decode(data, size); +} + +bool Base94OutputStream::Flush() { + flushed_ = true; + if (flush_needed_) { + flush_needed_ = false; + if (!((mode_ == Mode::kEncode) ? FinishEncoding() : FinishDecoding())) + return false; + } + return output_stream_->Flush(); +} + +bool Base94OutputStream::Encode(const uint8_t* data, size_t size) { + const uint8_t* cur = data; + while (size--) { + bit_buf_ |= *(cur++) << bit_count_; + bit_count_ += 8; + if (bit_count_ < 14) + continue; + + uint16_t block; + // Check if 13-bit or 14-bit data should be encoded. + if ((bit_buf_ & 0x1FFF) > kMaxValueOf14BitEncoding) { + block = bit_buf_ & 0x1FFF; + bit_buf_ >>= 13; + bit_count_ -= 13; + } else { + block = bit_buf_ & 0x3FFF; + bit_buf_ >>= 14; + bit_count_ -= 14; + } + buffer_.push_back(EncodeByte(block % 94)); + buffer_.push_back(EncodeByte(base::saturated_cast<uint8_t>(block / 94))); + + if (buffer_.size() > kMaxBuffer - 2 && !WriteOutputStream()) + return false; + } + return WriteOutputStream(); +} + +bool Base94OutputStream::Decode(const uint8_t* data, size_t size) { + const uint8_t* cur = data; + while (size--) { + if (DecodeByte(*cur) == 94) { + LOG(ERROR) << "Decode: invalid input"; + return false; + } + if (symbol_buffer_ == 0) { + symbol_buffer_ = *cur; + cur++; + continue; + } + uint16_t v = DecodeByte(symbol_buffer_) + DecodeByte(*cur) * 94; + cur++; + symbol_buffer_ = 0; + bit_buf_ |= v << bit_count_; + bit_count_ += (v & 0x1FFF) > kMaxValueOf14BitEncoding ? 13 : 14; + while (bit_count_ > 7) { + buffer_.push_back(bit_buf_ & 0xff); + bit_buf_ >>= 8; + bit_count_ -= 8; + } + if (buffer_.size() > kMaxBuffer - 2) { + if (!WriteOutputStream()) + return false; + } + } + return WriteOutputStream(); +} + +bool Base94OutputStream::FinishEncoding() { + if (bit_count_ == 0) + return true; + // Up to 13 bits data is left over. + buffer_.push_back(EncodeByte(bit_buf_ % 94)); + if (bit_buf_ > 93 || bit_count_ > 8) + buffer_.push_back(EncodeByte(base::saturated_cast<uint8_t>(bit_buf_ / 94))); + bit_count_ = 0; + bit_buf_ = 0; + return WriteOutputStream(); +} + +bool Base94OutputStream::FinishDecoding() { + // The left over bit is padding and all zero, if there is no symbol + // unprocessed. + if (symbol_buffer_ == 0) { + DCHECK(!bit_buf_); + return true; + } + bit_buf_ |= DecodeByte(symbol_buffer_) << bit_count_; + buffer_.push_back(bit_buf_ & 0xff); + bit_buf_ >>= 8; + // The remaining bits are either encode padding or zeros from bit shift. + DCHECK(!bit_buf_); + return WriteOutputStream(); +} + +bool Base94OutputStream::WriteOutputStream() { + if (buffer_.empty()) + return true; + + bool result = output_stream_->Write(buffer_.data(), buffer_.size()); + buffer_.clear(); + return result; +} + +} // namespace crashpad diff --git a/util/stream/base94_output_stream.h b/util/stream/base94_output_stream.h new file mode 100644 index 00000000..9d27b2ac --- /dev/null +++ b/util/stream/base94_output_stream.h @@ -0,0 +1,79 @@ +// 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_UTIL_STREAM_BASE94_OUTPUT_STREAM_H_ +#define CRASHPAD_UTIL_STREAM_BASE94_OUTPUT_STREAM_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "util/stream/output_stream_interface.h" + +namespace crashpad { + +//! \brief This class implements Base94 encoding/decoding, it uses all +//! printable characters except space for encoding, and no padding is required. +//! +//! This implementation uses two base94 symbols to encoding 13 or 14 bit data, +//! To maximize encoding efficiency, 14-bit data is encoded into two base94 +//! symbols if its low 13-bit is less than 644 ( = 94^2 - 2^13), otherwise +//! 13-bit data is encoded. +class Base94OutputStream : public OutputStreamInterface { + public: + //! \brief Whether this object is configured to encode or decode data. + enum class Mode : bool { + //! \brief Data passed through this object is encoded. + kEncode = false, + //! \brief Data passed through this object is decoded. + kDecode = true + }; + + //! \param[in] mode The work mode of this object. + //! \param[in] output_stream The output_stream that this object writes to. + Base94OutputStream(Mode mode, + std::unique_ptr<OutputStreamInterface> output_stream); + ~Base94OutputStream() override; + + // OutputStreamInterface: + bool Write(const uint8_t* data, size_t size) override; + bool Flush() override; + + private: + bool Encode(const uint8_t* data, size_t size); + bool Decode(const uint8_t* data, size_t size); + bool FinishEncoding(); + bool FinishDecoding(); + // Write encoded/decoded data to |output_stream_| and empty the |buffer_|. + bool WriteOutputStream(); + + Mode mode_; + std::unique_ptr<OutputStreamInterface> output_stream_; + std::vector<uint8_t> buffer_; + uint32_t bit_buf_; + // The number of valid bit in bit_buf_. + size_t bit_count_; + char symbol_buffer_; + bool flush_needed_; + bool flushed_; + + DISALLOW_COPY_AND_ASSIGN(Base94OutputStream); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_STREAM_BASE94_OUTPUT_STREAM_H_ diff --git a/util/stream/base94_output_stream_test.cc b/util/stream/base94_output_stream_test.cc new file mode 100644 index 00000000..32decbba --- /dev/null +++ b/util/stream/base94_output_stream_test.cc @@ -0,0 +1,290 @@ +// 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. + +#include "util/stream/base94_output_stream.h" + +#include <string.h> + +#include <algorithm> +#include <sstream> + +#include "base/macros.h" +#include "base/rand_util.h" +#include "base/stl_util.h" +#include "base/strings/stringprintf.h" +#include "gtest/gtest.h" +#include "util/stream/test_output_stream.h" + +namespace crashpad { +namespace test { +namespace { + +constexpr size_t kLongDataLength = 4096 * 10; + +std::string DumpInput(const uint8_t* input, size_t size) { + std::stringstream s; + size_t index = 0; + size_t byte_count = 0; + while (index < size) { + s << "0x" << std::hex << static_cast<int>(*(input + index++)) << ","; + if (byte_count++ > 1024) { + s << "\n"; + byte_count = 0; + } + } + return s.str(); +} + +class Base94OutputStreamTest : public testing::Test { + public: + Base94OutputStreamTest() {} + + protected: + void SetUp() override { + auto output_stream = std::make_unique<TestOutputStream>(); + encode_test_output_stream_ = output_stream.get(); + encoder_ = std::make_unique<Base94OutputStream>( + Base94OutputStream::Mode::kEncode, std::move(output_stream)); + output_stream = std::make_unique<TestOutputStream>(); + decode_test_output_stream_ = output_stream.get(); + decoder_ = std::make_unique<Base94OutputStream>( + Base94OutputStream::Mode::kDecode, std::move(output_stream)); + output_stream = std::make_unique<TestOutputStream>(); + round_trip_test_output_stream_ = output_stream.get(); + round_trip_ = std::make_unique<Base94OutputStream>( + Base94OutputStream::Mode::kEncode, + std::make_unique<Base94OutputStream>(Base94OutputStream::Mode::kDecode, + std::move(output_stream))); + } + + const uint8_t* BuildDeterministicInput(size_t size) { + deterministic_input_ = std::make_unique<uint8_t[]>(size); + uint8_t* deterministic_input_base = deterministic_input_.get(); + while (size-- > 0) + deterministic_input_base[size] = static_cast<uint8_t>(size); + return deterministic_input_base; + } + + const uint8_t* BuildRandomInput(size_t size) { + input_ = std::make_unique<uint8_t[]>(size); + base::RandBytes(&input_[0], size); + return input_.get(); + } + + Base94OutputStream* round_trip() const { return round_trip_.get(); } + const TestOutputStream& round_trip_test_output_stream() const { + return *round_trip_test_output_stream_; + } + + static void VerifyEncoding(const TestOutputStream& out, + const std::string& expected) { + EXPECT_EQ(out.all_data().size(), expected.size()); + EXPECT_EQ(memcmp(out.all_data().data(), expected.data(), expected.size()), + 0); + } + + static void VerifyDecoding(const TestOutputStream& out, + const std::vector<uint8_t>& expected) { + EXPECT_EQ(out.all_data().size(), expected.size()); + EXPECT_EQ(memcmp(out.all_data().data(), expected.data(), expected.size()), + 0); + } + + void RunTest(const std::string& text, const std::vector<uint8_t>& binary) { + EXPECT_TRUE(encoder_->Write(binary.data(), binary.size())); + EXPECT_TRUE(encoder_->Flush()); + VerifyEncoding(*encode_test_output_stream_, text); + EXPECT_TRUE(decoder_->Write(reinterpret_cast<const uint8_t*>(text.data()), + text.size())); + EXPECT_TRUE(decoder_->Flush()); + VerifyDecoding(*decode_test_output_stream_, binary); + } + + void VerifyRoundTrip(const std::vector<uint8_t>& expected) { + TestOutputStream* out = round_trip_test_output_stream_; + EXPECT_EQ(out->all_data().size(), expected.size()); + EXPECT_EQ(memcmp(out->all_data().data(), expected.data(), expected.size()), + 0); + } + + private: + std::unique_ptr<Base94OutputStream> encoder_; + std::unique_ptr<Base94OutputStream> decoder_; + std::unique_ptr<Base94OutputStream> round_trip_; + TestOutputStream* encode_test_output_stream_; + TestOutputStream* decode_test_output_stream_; + TestOutputStream* round_trip_test_output_stream_; + std::unique_ptr<uint8_t[]> input_; + std::unique_ptr<uint8_t[]> deterministic_input_; + + DISALLOW_COPY_AND_ASSIGN(Base94OutputStreamTest); +}; + +TEST_F(Base94OutputStreamTest, Encoding) { + std::vector<uint8_t> binary = {0x0}; + std::string text("!"); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Encoding1) { + std::vector<uint8_t> binary = {0x0, 0x0}; + std::string text("!!!"); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Encoding2) { + std::vector<uint8_t> binary = {0x0, 0x0, 0x0}; + std::string text("!!!!"); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Encoding3) { + std::vector<uint8_t> binary = {0x0, 0x0, 0x0, 0x0}; + std::string text("!!!!!"); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Encoding4) { + std::vector<uint8_t> binary = {0x0, 0x0, 0x0, 0x0, 0x0}; + std::string text("!!!!!!"); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Encoding10) { + std::vector<uint8_t> binary = {0xFF}; + std::string text("d#"); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Encoding11) { + std::vector<uint8_t> binary = {0xFF, 0xFF}; + std::string text(".x("); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Encoding12) { + std::vector<uint8_t> binary = {0xFF, 0xFF, 0xFF}; + std::string text(".xj6"); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Encoding13) { + std::vector<uint8_t> binary = {0xFF, 0xFF, 0xFF, 0xFF}; + std::string text(".x.x`"); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Encoding14) { + std::vector<uint8_t> binary = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + std::string text(".x.x.x\""); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, Printable94) { + std::vector<uint8_t> binary = { + 0x5e, 0x0, 0x47, 0xa0, 0x1d, 0x60, 0xa, 0xab, 0x41, 0x41, 0xa4, 0x9, + 0x64, 0x71, 0x32, 0xc, 0x47, 0xf9, 0x20, 0x22, 0xa3, 0x44, 0xa0, 0x84, + 0x15, 0xe0, 0xf2, 0x61, 0xfc, 0x4c, 0xb7, 0xe1, 0x39, 0x9b, 0x47, 0xff, + 0x64, 0x21, 0x5c, 0x74, 0x91, 0xec, 0x52, 0x75, 0xa2, 0x51, 0x93, 0x4a, + 0x5e, 0x45, 0x2d, 0xd8, 0xf5, 0xc0, 0xdc, 0x58, 0x33, 0x63, 0x69, 0x8b, + 0x4d, 0xbd, 0x25, 0x39, 0x54, 0x77, 0xf0, 0xcc, 0x5e, 0xf1, 0x23, 0x81, + 0x6, 0x21, 0x71, 0x28, 0x28, 0x2}; + std::string text( + "!\"#$%&'()*+,-./" + "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" + "abcdefghijklmnopqrstuvwxyz{|}~!"); + RunTest(text, binary); +} + +TEST_F(Base94OutputStreamTest, WriteLongDataMultipleTimes) { + const uint8_t* input = BuildRandomInput(kLongDataLength); + SCOPED_TRACE(base::StringPrintf("Input: %s", + DumpInput(input, kLongDataLength).c_str())); + // Call Write() a random number of times. + size_t index = 0; + while (index < kLongDataLength) { + size_t write_length = + std::min(static_cast<size_t>(base::RandInt(0, 4096 * 2)), + kLongDataLength - index); + SCOPED_TRACE( + base::StringPrintf("index %zu, write_length %zu", index, write_length)); + EXPECT_TRUE(round_trip()->Write(input + index, write_length)); + index += write_length; + } + EXPECT_TRUE(round_trip()->Flush()); + EXPECT_EQ(round_trip_test_output_stream().all_data().size(), kLongDataLength); + EXPECT_EQ(memcmp(round_trip_test_output_stream().all_data().data(), + input, + kLongDataLength), + 0); +} + +TEST_F(Base94OutputStreamTest, WriteDeterministicLongDataMultipleTimes) { + const uint8_t* input = BuildDeterministicInput(kLongDataLength); + + static constexpr size_t kWriteLengths[] = { + 4, 96, 40, kLongDataLength - 4 - 96 - 40}; + + size_t offset = 0; + for (size_t index = 0; index < base::size(kWriteLengths); ++index) { + const size_t write_length = kWriteLengths[index]; + SCOPED_TRACE(base::StringPrintf( + "offset %zu, write_length %zu", offset, write_length)); + EXPECT_TRUE(round_trip()->Write(input + offset, write_length)); + offset += write_length; + } + EXPECT_TRUE(round_trip()->Flush()); + EXPECT_EQ(round_trip_test_output_stream().all_data().size(), kLongDataLength); + EXPECT_EQ(memcmp(round_trip_test_output_stream().all_data().data(), + input, + kLongDataLength), + 0); +} + +TEST_F(Base94OutputStreamTest, NoWriteOrFlush) { + EXPECT_EQ(round_trip_test_output_stream().write_count(), 0u); + EXPECT_EQ(round_trip_test_output_stream().flush_count(), 0u); + EXPECT_TRUE(round_trip_test_output_stream().all_data().empty()); +} + +TEST_F(Base94OutputStreamTest, FlushWithoutWrite) { + EXPECT_TRUE(round_trip()->Flush()); + EXPECT_EQ(round_trip_test_output_stream().write_count(), 0u); + EXPECT_EQ(round_trip_test_output_stream().flush_count(), 1u); + EXPECT_TRUE(round_trip_test_output_stream().all_data().empty()); +} + +TEST_F(Base94OutputStreamTest, WriteEmptyData) { + std::vector<uint8_t> empty_data; + EXPECT_TRUE(round_trip()->Write( + static_cast<const uint8_t*>(empty_data.data()), empty_data.size())); + EXPECT_TRUE(round_trip()->Flush()); + EXPECT_TRUE(round_trip()->Flush()); + EXPECT_EQ(round_trip_test_output_stream().write_count(), 0u); + EXPECT_EQ(round_trip_test_output_stream().flush_count(), 2u); + EXPECT_TRUE(round_trip_test_output_stream().all_data().empty()); +} + +TEST_F(Base94OutputStreamTest, Process7bitsInFinishDecoding) { + std::vector<uint8_t> input = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + EXPECT_TRUE(round_trip()->Write(static_cast<const uint8_t*>(input.data()), + input.size())); + EXPECT_TRUE(round_trip()->Flush()); + VerifyRoundTrip(input); +} + +} // namespace +} // namespace test +} // namespace crashpad From c6153f0b6e72d0ca187bc6d00009232bd49770d0 Mon Sep 17 00:00:00 2001 From: James Forshaw <forshaw@chromium.org> Date: Tue, 10 Dec 2019 08:51:20 -0800 Subject: [PATCH 300/401] [Windows] Add AppContainer SID to Named Pipe DACL. This CL modifies the creation of the Named Pipe Security Descriptor to allow access from AppContainer processes. The DACL only allows access for the current user and SYSTEM which matches up with the auto-assigned DACL used previously (the read-only logon SID ACE has been removed). As this new code uses APIs from ADVAPI32 a check is made to ensure it's not being called while the loader lock is held to avoid hitting previous similar issues. Bug: crashpad: 318 Change-Id: I3f9cf5c788dbadacad21c8a2d57a0188f690ac32 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1955982 Commit-Queue: James Forshaw <forshaw@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/win/registration_protocol_win.cc | 81 ++++++++++++++-- util/win/registration_protocol_win.h | 17 +++- util/win/registration_protocol_win_test.cc | 108 ++++++++++++++++++++- 3 files changed, 192 insertions(+), 14 deletions(-) diff --git a/util/win/registration_protocol_win.cc b/util/win/registration_protocol_win.cc index 359e3308..64ed518b 100644 --- a/util/win/registration_protocol_win.cc +++ b/util/win/registration_protocol_win.cc @@ -14,16 +14,63 @@ #include "util/win/registration_protocol_win.h" -#include <stddef.h> #include <windows.h> +#include <aclapi.h> +#include <sddl.h> +#include <stddef.h> #include "base/logging.h" #include "base/stl_util.h" #include "util/win/exception_handler_server.h" +#include "util/win/loader_lock.h" #include "util/win/scoped_handle.h" +#include "util/win/scoped_local_alloc.h" namespace crashpad { +namespace { + +void* GetSecurityDescriptorWithUser(const base::char16* sddl_string, + size_t* size) { + if (size) + *size = 0; + + PSECURITY_DESCRIPTOR base_sec_desc; + if (!ConvertStringSecurityDescriptorToSecurityDescriptor( + sddl_string, SDDL_REVISION_1, &base_sec_desc, nullptr)) { + PLOG(ERROR) << "ConvertStringSecurityDescriptorToSecurityDescriptor"; + return nullptr; + } + + ScopedLocalAlloc base_sec_desc_owner(base_sec_desc); + EXPLICIT_ACCESS access; + wchar_t username[] = L"CURRENT_USER"; + BuildExplicitAccessWithName( + &access, username, GENERIC_ALL, GRANT_ACCESS, NO_INHERITANCE); + + PSECURITY_DESCRIPTOR user_sec_desc; + ULONG user_sec_desc_size; + DWORD error = BuildSecurityDescriptor(nullptr, + nullptr, + 1, + &access, + 0, + nullptr, + base_sec_desc, + &user_sec_desc_size, + &user_sec_desc); + if (error != ERROR_SUCCESS) { + SetLastError(error); + PLOG(ERROR) << "BuildSecurityDescriptor"; + return nullptr; + } + + *size = user_sec_desc_size; + return user_sec_desc; +} + +} // namespace + bool SendToCrashHandlerServer(const base::string16& pipe_name, const ClientToServerMessage& message, ServerToClientMessage* response) { @@ -124,16 +171,11 @@ HANDLE CreateNamedPipeInstance(const std::wstring& pipe_name, security_attributes_pointer); } -const void* GetSecurityDescriptorForNamedPipeInstance(size_t* size) { +const void* GetFallbackSecurityDescriptorForNamedPipeInstance(size_t* size) { // Mandatory Label, no ACE flags, no ObjectType, integrity level untrusted is - // "S:(ML;;;;;S-1-16-0)". Typically - // ConvertStringSecurityDescriptorToSecurityDescriptor() would be used to - // convert from a string representation. However, that function cannot be used - // because it is in advapi32.dll and CreateNamedPipeInstance() is called from - // within DllMain() where the loader lock is held. advapi32.dll is delay - // loaded in chrome_elf.dll because it must avoid loading user32.dll. If an - // advapi32.dll function were used, it would cause a load of the DLL, which - // would in turn cause deadlock. + // "S:(ML;;;;;S-1-16-0)". This static security descriptor is used as a + // fallback if GetSecurityDescriptorWithUser fails, to avoid losing crashes + // from non-AppContainer sandboxed applications. #pragma pack(push, 1) static constexpr struct SecurityDescriptorBlob { @@ -207,4 +249,23 @@ const void* GetSecurityDescriptorForNamedPipeInstance(size_t* size) { return reinterpret_cast<const void*>(&kSecDescBlob); } +const void* GetSecurityDescriptorForNamedPipeInstance(size_t* size) { + CHECK(!IsThreadInLoaderLock()); + + // Get a security descriptor which grants the current user and SYSTEM full + // access to the named pipe. Also grant AppContainer RW access through the ALL + // APPLICATION PACKAGES SID (S-1-15-2-1). Finally add an Untrusted Mandatory + // Label for non-AppContainer sandboxed users. + static size_t sd_size; + static void* sec_desc = GetSecurityDescriptorWithUser( + L"D:(A;;GA;;;SY)(A;;GWGR;;;S-1-15-2-1)S:(ML;;;;;S-1-16-0)", &sd_size); + + if (!sec_desc) + return GetFallbackSecurityDescriptorForNamedPipeInstance(size); + + if (size) + *size = sd_size; + return sec_desc; +} + } // namespace crashpad diff --git a/util/win/registration_protocol_win.h b/util/win/registration_protocol_win.h index 5f04a466..ef8bebc1 100644 --- a/util/win/registration_protocol_win.h +++ b/util/win/registration_protocol_win.h @@ -145,10 +145,10 @@ bool SendToCrashHandlerServer(const base::string16& pipe_name, HANDLE CreateNamedPipeInstance(const std::wstring& pipe_name, bool first_instance); -//! \brief Returns the SECURITY_DESCRIPTOR blob that will be used for creating +//! \brief Returns the `SECURITY_DESCRIPTOR` blob that will be used for creating //! the connection pipe in CreateNamedPipeInstance(). //! -//! This function is exposed for only for testing. +//! This function is only exposed for testing. //! //! \param[out] size The size of the returned blob. May be `nullptr` if not //! required. @@ -157,6 +157,19 @@ HANDLE CreateNamedPipeInstance(const std::wstring& pipe_name, //! transferred to the caller. const void* GetSecurityDescriptorForNamedPipeInstance(size_t* size); +//! \brief Returns the `SECURITY_DESCRIPTOR` blob that will be used for creating +//! the connection pipe in CreateNamedPipeInstance() if the full descriptor +//! can't be created. +//! +//! This function is only exposed for testing. +//! +//! \param[out] size The size of the returned blob. May be `nullptr` if not +//! required. +//! +//! \return A pointer to a self-relative `SECURITY_DESCRIPTOR`. Ownership is not +//! transferred to the caller. +const void* GetFallbackSecurityDescriptorForNamedPipeInstance(size_t* size); + } // namespace crashpad #endif // CRASHPAD_UTIL_WIN_REGISTRATION_PROTOCOL_WIN_H_ diff --git a/util/win/registration_protocol_win_test.cc b/util/win/registration_protocol_win_test.cc index 6601b4e7..334d7d83 100644 --- a/util/win/registration_protocol_win_test.cc +++ b/util/win/registration_protocol_win_test.cc @@ -14,18 +14,122 @@ #include "util/win/registration_protocol_win.h" -#include <windows.h> +#include <aclapi.h> #include <sddl.h> #include <string.h> +#include <windows.h> +#include <vector> + +#include "base/logging.h" +#include "base/strings/string16.h" #include "gtest/gtest.h" #include "test/errors.h" +#include "util/win/scoped_handle.h" #include "util/win/scoped_local_alloc.h" namespace crashpad { namespace test { namespace { +base::string16 GetStringFromSid(PSID sid) { + LPWSTR sid_str; + if (!ConvertSidToStringSid(sid, &sid_str)) { + PLOG(ERROR) << "ConvertSidToStringSid"; + return base::string16(); + } + ScopedLocalAlloc sid_str_ptr(sid_str); + return sid_str; +} + +base::string16 GetUserSidString() { + HANDLE token_handle; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token_handle)) { + PLOG(ERROR) << "OpenProcessToken"; + return base::string16(); + } + + ScopedKernelHANDLE token(token_handle); + DWORD user_size = 0; + GetTokenInformation(token.get(), TokenUser, nullptr, 0, &user_size); + if (user_size == 0) { + PLOG(ERROR) << "GetTokenInformation Size"; + return base::string16(); + } + + std::vector<char> user(user_size); + if (!GetTokenInformation( + token.get(), TokenUser, user.data(), user_size, &user_size)) { + PLOG(ERROR) << "GetTokenInformation"; + return base::string16(); + } + + TOKEN_USER* user_ptr = reinterpret_cast<TOKEN_USER*>(user.data()); + return GetStringFromSid(user_ptr->User.Sid); +} + +void CheckAce(PACL acl, + DWORD index, + BYTE check_ace_type, + ACCESS_MASK check_mask, + const base::string16& check_sid) { + ASSERT_FALSE(check_sid.empty()); + void* ace_ptr; + ASSERT_TRUE(GetAce(acl, index, &ace_ptr)); + + ACE_HEADER* header = static_cast<ACE_HEADER*>(ace_ptr); + ASSERT_EQ(check_ace_type, header->AceType); + ASSERT_EQ(0, header->AceFlags); + + PSID sid = nullptr; + ACCESS_MASK mask = 0; + switch (header->AceType) { + case ACCESS_ALLOWED_ACE_TYPE: { + ACCESS_ALLOWED_ACE* allowed_ace = + static_cast<ACCESS_ALLOWED_ACE*>(ace_ptr); + sid = &allowed_ace->SidStart; + mask = allowed_ace->Mask; + } break; + case SYSTEM_MANDATORY_LABEL_ACE_TYPE: { + SYSTEM_MANDATORY_LABEL_ACE* label_ace = + static_cast<SYSTEM_MANDATORY_LABEL_ACE*>(ace_ptr); + sid = &label_ace->SidStart; + mask = label_ace->Mask; + } break; + default: + NOTREACHED(); + break; + } + + ASSERT_EQ(check_mask, mask); + ASSERT_EQ(check_sid, GetStringFromSid(sid)); +} + +TEST(SecurityDescriptor, NamedPipeDefault) { + const void* sec_desc = GetSecurityDescriptorForNamedPipeInstance(nullptr); + + PACL acl; + BOOL acl_present; + BOOL acl_defaulted; + ASSERT_TRUE(GetSecurityDescriptorDacl( + const_cast<void*>(sec_desc), &acl_present, &acl, &acl_defaulted)); + ASSERT_EQ(3, acl->AceCount); + CheckAce(acl, 0, ACCESS_ALLOWED_ACE_TYPE, GENERIC_ALL, GetUserSidString()); + // Check SYSTEM user SID. + CheckAce(acl, 1, ACCESS_ALLOWED_ACE_TYPE, GENERIC_ALL, L"S-1-5-18"); + // Check ALL APPLICATION PACKAGES group SID. + CheckAce(acl, + 2, + ACCESS_ALLOWED_ACE_TYPE, + GENERIC_READ | GENERIC_WRITE, + L"S-1-15-2-1"); + + ASSERT_TRUE(GetSecurityDescriptorSacl( + const_cast<void*>(sec_desc), &acl_present, &acl, &acl_defaulted)); + ASSERT_EQ(1, acl->AceCount); + CheckAce(acl, 0, SYSTEM_MANDATORY_LABEL_ACE_TYPE, 0, L"S-1-16-0"); +} + TEST(SecurityDescriptor, MatchesAdvapi32) { // This security descriptor is built manually in the connection code to avoid // calling the advapi32 functions. Verify that it returns the same thing as @@ -43,7 +147,7 @@ TEST(SecurityDescriptor, MatchesAdvapi32) { size_t created_len; const void* const created = - GetSecurityDescriptorForNamedPipeInstance(&created_len); + GetFallbackSecurityDescriptorForNamedPipeInstance(&created_len); ASSERT_EQ(created_len, sec_desc_len); EXPECT_EQ(memcmp(sec_desc, created, sec_desc_len), 0); } From 097395dfca271f0d54a688f97f1baf2f235e3b3d Mon Sep 17 00:00:00 2001 From: Benjamin Wright <benwright@google.com> Date: Tue, 10 Dec 2019 16:30:26 -0800 Subject: [PATCH 301/401] [crashpad] - Replace "system-temp" with "isolated-temp" Bug: fuchsia:25092 Change-Id: I553245cea7b4db7e414320bfed02e79531cbc4c9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1961139 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- test/fuchsia_crashpad_tests.cmx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fuchsia_crashpad_tests.cmx b/test/fuchsia_crashpad_tests.cmx index b0edbb46..d1870982 100644 --- a/test/fuchsia_crashpad_tests.cmx +++ b/test/fuchsia_crashpad_tests.cmx @@ -12,7 +12,7 @@ }, "sandbox": { "features": [ - "system-temp", + "isolated-temp", "deprecated-ambient-replace-as-executable" ], "services": [ From fa28ef896cd7690dc9af0383d9f987ce7ff73ada Mon Sep 17 00:00:00 2001 From: Tao Bai <michaelbai@chromium.org> Date: Thu, 12 Dec 2019 13:15:05 -0800 Subject: [PATCH 302/401] [log minidump] LogOutputStream implementation Emit the received data to Android logcat in Android, and noop for other platforms. Bug: crashpad:308 Change-Id: I6e46e2fa8bd61f93f614ad0bfb6441a79139b04b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1958711 Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- util/BUILD.gn | 3 + util/stream/log_output_stream.cc | 130 ++++++++++++++++++++++++++ util/stream/log_output_stream.h | 61 ++++++++++++ util/stream/log_output_stream_test.cc | 126 +++++++++++++++++++++++++ 4 files changed, 320 insertions(+) create mode 100644 util/stream/log_output_stream.cc create mode 100644 util/stream/log_output_stream.h create mode 100644 util/stream/log_output_stream_test.cc diff --git a/util/BUILD.gn b/util/BUILD.gn index 3317f7cc..e24b675c 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -168,6 +168,8 @@ static_library("util") { "stdlib/thread_safe_vector.h", "stream/base94_output_stream.cc", "stream/base94_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", @@ -591,6 +593,7 @@ source_set("util_test") { "stdlib/strnlen_test.cc", "stdlib/thread_safe_vector_test.cc", "stream/base94_output_stream_test.cc", + "stream/log_output_stream_test.cc", "stream/test_output_stream.cc", "stream/test_output_stream.h", "stream/zlib_output_stream_test.cc", diff --git a/util/stream/log_output_stream.cc b/util/stream/log_output_stream.cc new file mode 100644 index 00000000..03c0a5a0 --- /dev/null +++ b/util/stream/log_output_stream.cc @@ -0,0 +1,130 @@ +// 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. + +#include "util/stream/log_output_stream.h" + +#include <algorithm> + +#include "base/logging.h" + +#if defined(OS_ANDROID) +#include <android/log.h> +#endif + +namespace crashpad { + +namespace { + +// Most minidumps are expected to be compressed and encoded into less than 128k. +constexpr size_t kOutputCap = 128 * 1024; + +// From Android NDK r20 <android/log.h>, log message text may be truncated to +// less than an implementation-specific limit (1023 bytes), for sake of safe +// and being easy to read in logcat, choose 512. +constexpr size_t kLineBufferSize = 512; + +} // namespace + +LogOutputStream::LogOutputStream() + : output_count_(0), flush_needed_(false), flushed_(false) { + buffer_.reserve(kLineBufferSize); +} + +LogOutputStream::~LogOutputStream() { + DCHECK(!flush_needed_); +} + +bool LogOutputStream::Write(const uint8_t* data, size_t size) { + DCHECK(!flushed_); + flush_needed_ = true; + while (size > 0) { + size_t m = std::min(kLineBufferSize - buffer_.size(), size); + buffer_.append(reinterpret_cast<const char*>(data), m); + data += m; + size -= m; + if (buffer_.size() == kLineBufferSize && !WriteBuffer()) { + flush_needed_ = false; + LOG(ERROR) << "Write: exceeds cap."; + if (output_stream_for_testing_) + output_stream_for_testing_->Flush(); + return false; + } + } + return true; +} + +bool LogOutputStream::WriteBuffer() { + if (output_count_ == 0) { + if (!WriteToLog("-----BEGIN CRASHPAD MINIDUMP-----")) + return false; + } + + if (buffer_.empty()) + return true; + + output_count_ += buffer_.size(); + if (output_count_ > kOutputCap) { + WriteToLog("-----ABORT CRASHPAD MINIDUMP-----"); + return false; + } + + bool result = WriteToLog(buffer_.c_str()); + buffer_.clear(); + return result; +} + +bool LogOutputStream::WriteToLog(const char* buf) { +#if defined(OS_ANDROID) + int ret = + __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, "crashpad", buf); + if (ret < 0) { + errno = -ret; + PLOG(ERROR) << "__android_log_buf_write"; + return false; + } +#endif + // For testing. + if (output_stream_for_testing_) { + return output_stream_for_testing_->Write( + reinterpret_cast<const uint8_t*>(buf), strlen(buf)); + } + return true; +} + +bool LogOutputStream::Flush() { + flush_needed_ = false; + flushed_ = true; + + bool result = true; + if (WriteBuffer()) { + result = WriteToLog("-----END CRASHPAD MINIDUMP-----"); + } else { + LOG(ERROR) << "Flush: exceeds cap."; + result = false; + } + + // Since output_stream_for_testing_'s Write() method has been called, its + // Flush() shall always be invoked. + if (output_stream_for_testing_) + output_stream_for_testing_->Flush(); + + return result; +} + +void LogOutputStream::SetOutputStreamForTesting( + std::unique_ptr<OutputStreamInterface> stream) { + output_stream_for_testing_ = std::move(stream); +} + +} // namespace crashpad diff --git a/util/stream/log_output_stream.h b/util/stream/log_output_stream.h new file mode 100644 index 00000000..4a91f5c1 --- /dev/null +++ b/util/stream/log_output_stream.h @@ -0,0 +1,61 @@ +// 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_UTIL_STREAM_LOG_OUTPUT_STREAM_H_ +#define CRASHPAD_UTIL_STREAM_LOG_OUTPUT_STREAM_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> + +#include "base/macros.h" +#include "util/stream/output_stream_interface.h" + +namespace crashpad { + +//! \brief This class output the received data to Android log, NOP in other +//! platform. +//! +//! To avoid overflowing Android log, total 128k log data is allowed, after +//! that cap, the output is aborted. +class LogOutputStream : public OutputStreamInterface { + public: + LogOutputStream(); + ~LogOutputStream() override; + + // OutputStreamInterface: + bool Write(const uint8_t* data, size_t size) override; + bool Flush() override; + + void SetOutputStreamForTesting(std::unique_ptr<OutputStreamInterface> stream); + + private: + // Flush the |buffer_|, return false if kOutputCap meet. + bool WriteBuffer(); + bool WriteToLog(const char* buf); + + std::string buffer_; + size_t output_count_; + bool flush_needed_; + bool flushed_; + std::unique_ptr<OutputStreamInterface> output_stream_for_testing_; + + DISALLOW_COPY_AND_ASSIGN(LogOutputStream); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_STREAM_LOG_OUTPUT_STREAM_H_ diff --git a/util/stream/log_output_stream_test.cc b/util/stream/log_output_stream_test.cc new file mode 100644 index 00000000..510df764 --- /dev/null +++ b/util/stream/log_output_stream_test.cc @@ -0,0 +1,126 @@ +// 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. + +#include "util/stream/log_output_stream.h" + +#include <algorithm> +#include <memory> +#include <string> + +#include "base/macros.h" +#include "gtest/gtest.h" +#include "util/stream/test_output_stream.h" + +namespace crashpad { +namespace test { +namespace { + +constexpr size_t kOutputCap = 128 * 1024; +constexpr size_t kLineBufferSize = 512; +const char* kBeginGuard = "-----BEGIN CRASHPAD MINIDUMP-----"; +const char* kEndGuard = "-----END CRASHPAD MINIDUMP-----"; +const char* kAbortGuard = "-----ABORT CRASHPAD MINIDUMP-----"; + +std::string ConvertToString(const std::vector<uint8_t>& src) { + return std::string(reinterpret_cast<const char*>(src.data()), src.size()); +} + +class LogOutputStreamTest : public testing::Test { + public: + LogOutputStreamTest() : test_output_stream_(nullptr) {} + + protected: + void SetUp() override { + std::unique_ptr<TestOutputStream> output_stream = + std::make_unique<TestOutputStream>(); + test_output_stream_ = output_stream.get(); + log_stream_ = std::make_unique<LogOutputStream>(); + log_stream_->SetOutputStreamForTesting(std::move(output_stream)); + } + + const uint8_t* BuildDeterministicInput(size_t size) { + deterministic_input_ = std::make_unique<uint8_t[]>(size); + uint8_t* deterministic_input_base = deterministic_input_.get(); + while (size-- > 0) + deterministic_input_base[size] = static_cast<uint8_t>('a'); + return deterministic_input_base; + } + + TestOutputStream* test_output_stream() const { return test_output_stream_; } + + LogOutputStream* log_stream() const { return log_stream_.get(); } + + private: + std::unique_ptr<LogOutputStream> log_stream_; + TestOutputStream* test_output_stream_; + std::unique_ptr<uint8_t[]> deterministic_input_; + + DISALLOW_COPY_AND_ASSIGN(LogOutputStreamTest); +}; + +TEST_F(LogOutputStreamTest, VerifyGuards) { + log_stream()->Flush(); + // Verify OutputStream wrote 2 guards. + EXPECT_EQ(test_output_stream()->write_count(), 2u); + EXPECT_EQ(test_output_stream()->flush_count(), 1u); + EXPECT_FALSE(test_output_stream()->all_data().empty()); + EXPECT_EQ(ConvertToString(test_output_stream()->all_data()), + std::string(kBeginGuard).append(kEndGuard)); +} + +TEST_F(LogOutputStreamTest, WriteShortLog) { + const uint8_t* input = BuildDeterministicInput(2); + EXPECT_TRUE(log_stream()->Write(input, 2)); + EXPECT_TRUE(log_stream()->Flush()); + // Verify OutputStream wrote 2 guards and data. + EXPECT_EQ(test_output_stream()->write_count(), 3u); + EXPECT_EQ(test_output_stream()->flush_count(), 1u); + EXPECT_FALSE(test_output_stream()->all_data().empty()); + EXPECT_EQ(ConvertToString(test_output_stream()->all_data()), + std::string(kBeginGuard).append("aa").append(kEndGuard)); +} + +TEST_F(LogOutputStreamTest, WriteLongLog) { + size_t input_length = kLineBufferSize + kLineBufferSize / 2; + const uint8_t* input = BuildDeterministicInput(input_length); + // Verify OutputStream wrote 2 guards and data. + EXPECT_TRUE(log_stream()->Write(input, input_length)); + EXPECT_TRUE(log_stream()->Flush()); + EXPECT_EQ(test_output_stream()->write_count(), + 2 + input_length / kLineBufferSize + 1); + EXPECT_EQ(test_output_stream()->flush_count(), 1u); + EXPECT_EQ(test_output_stream()->all_data().size(), + strlen(kBeginGuard) + strlen(kEndGuard) + input_length); +} + +TEST_F(LogOutputStreamTest, WriteAbort) { + size_t input_length = kOutputCap + kLineBufferSize; + const uint8_t* input = BuildDeterministicInput(input_length); + EXPECT_FALSE(log_stream()->Write(input, input_length)); + std::string data(ConvertToString(test_output_stream()->all_data())); + EXPECT_EQ(data.substr(data.size() - strlen(kAbortGuard)), kAbortGuard); +} + +TEST_F(LogOutputStreamTest, FlushAbort) { + size_t input_length = kOutputCap + kLineBufferSize / 2; + const uint8_t* input = BuildDeterministicInput(input_length); + EXPECT_TRUE(log_stream()->Write(input, input_length)); + EXPECT_FALSE(log_stream()->Flush()); + std::string data(ConvertToString(test_output_stream()->all_data())); + EXPECT_EQ(data.substr(data.size() - strlen(kAbortGuard)), kAbortGuard); +} + +} // namespace +} // namespace test +} // namespace crashpad From af5d5468e005b035685f15641c15c33dd0a668a2 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 12 Dec 2019 14:34:11 -0800 Subject: [PATCH 303/401] Rename FIDL tables to .c due to use of designated initializers Will also need https://fuchsia-review.googlesource.com/c/fuchsia/+/348593 to land in the SDK to fix the bots. Very helpful link: https://ci.chromium.org/p/crashpad/builders/try/crashpad_try_fuchsia_arm64_dbg/728 Change-Id: Iacdbb13a72d116bd579f5f10cadbe7a0b3ed7987 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1966371 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- third_party/fuchsia/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index e96ec664..88866c62 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -134,7 +134,7 @@ if (crashpad_is_in_fuchsia) { cpp_stem = "$fidl_root_gen_dir/${fidl_source.header_stem}/cpp/fidl" cpp_header = "$cpp_stem.h" cpp_source = "$cpp_stem.cc" - coding_tables = "$fidl_stem/tables.cc" + coding_tables = "$fidl_stem/tables.c" # Compiles the .fidl file, outputs the intermediary JSON representation # and generates the C bindings. From a126f524fa825ac694f23fe459202fb26918d542 Mon Sep 17 00:00:00 2001 From: danakj <danakj@chromium.org> Date: Fri, 13 Dec 2019 12:38:15 -0500 Subject: [PATCH 304/401] Use base::BindOnce() instead of base::Bind() R=rsesek@chromium.org Bug: chromium:1007836 Change-Id: I1997bec5e4a499d2c200099e6cc94876a4667782 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1967540 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: danakj <danakj@chromium.org> --- test/gtest_main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gtest_main.cc b/test/gtest_main.cc index e65f9214..0a7a2d3a 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -80,7 +80,7 @@ int main(int argc, char* argv[]) { return base::LaunchUnitTests( argc, argv, - base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite))); + base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite))); } #endif // CRASHPAD_IS_IN_CHROMIUM From d3d0c8d3ca5b85c950e30a169a656129c553f117 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 13 Dec 2019 10:23:12 -0800 Subject: [PATCH 305/401] android: don't expect code addresses to be readable Change-Id: I252a93db5f4166216664ae8f67e331fc7eed8852 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1967548 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- util/linux/memory_map_test.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/util/linux/memory_map_test.cc b/util/linux/memory_map_test.cc index 20e5f227..0ee90800 100644 --- a/util/linux/memory_map_test.cc +++ b/util/linux/memory_map_test.cc @@ -101,7 +101,10 @@ TEST(MemoryMap, SelfBasic) { ASSERT_TRUE(mapping); EXPECT_GE(code_address, mapping->range.Base()); EXPECT_LT(code_address, mapping->range.End()); +#if !defined(OS_ANDROID) + // Android Q+ supports execute only memory. EXPECT_TRUE(mapping->readable); +#endif EXPECT_FALSE(mapping->writable); EXPECT_TRUE(mapping->executable); @@ -167,7 +170,10 @@ 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) + // Android Q+ supports execute only memory. EXPECT_TRUE(mapping->readable); +#endif EXPECT_TRUE(mapping->executable); EXPECT_FALSE(mapping->writable); From 4dd9124e2fa42c53e137cf831e5d9193f189b543 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 17 Dec 2019 12:16:44 -0800 Subject: [PATCH 306/401] linux: install handler and log errors on prctl failure Change-Id: Iec118ce299ad9a9cd81e3dea98b25804121b5b2b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1972311 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_linux.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/client/crashpad_client_linux.cc b/client/crashpad_client_linux.cc index 2adcefca..98c3d092 100644 --- a/client/crashpad_client_linux.cc +++ b/client/crashpad_client_linux.cc @@ -16,6 +16,7 @@ #include <fcntl.h> #include <stdlib.h> +#include <sys/prctl.h> #include <sys/socket.h> #include <sys/syscall.h> #include <sys/types.h> @@ -290,9 +291,17 @@ class RequestCrashDumpHandler : public SignalHandler { } pid = creds.pid; } - if (pid > 0 && client.SetPtracer(pid) != 0) { - LOG(ERROR) << "failed to set ptracer"; - return false; + 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. } sock_to_handler_.reset(sock.release()); handler_pid_ = pid; From b411976ca5f4291571c0cc446ee79c009b7a247c Mon Sep 17 00:00:00 2001 From: Tao Bai <michaelbai@chromium.org> Date: Wed, 18 Dec 2019 11:33:39 -0800 Subject: [PATCH 307/401] [log minidump] add tool to encode/decode minidump log. - This tool could compress/encode or decode/decompress the minidump log file, will be used by script to symbolize the crash. - Added FileOutputStream and FileEncoder. Bug: crashpad:308 Change-Id: I15c3e4908882a09983ec81a90e38249967c29fc4 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1968059 Commit-Queue: Tao Bai <michaelbai@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- tools/BUILD.gn | 13 +++ tools/base94_encoder.cc | 128 ++++++++++++++++++++++++++++++ util/BUILD.gn | 5 ++ util/stream/file_encoder.cc | 85 ++++++++++++++++++++ util/stream/file_encoder.h | 59 ++++++++++++++ util/stream/file_encoder_test.cc | 112 ++++++++++++++++++++++++++ util/stream/file_output_stream.cc | 45 +++++++++++ util/stream/file_output_stream.h | 46 +++++++++++ 8 files changed, 493 insertions(+) create mode 100644 tools/base94_encoder.cc create mode 100644 util/stream/file_encoder.cc create mode 100644 util/stream/file_encoder.h create mode 100644 util/stream/file_encoder_test.cc create mode 100644 util/stream/file_output_stream.cc create mode 100644 util/stream/file_output_stream.h diff --git a/tools/BUILD.gn b/tools/BUILD.gn index ffcd08f3..99332389 100644 --- a/tools/BUILD.gn +++ b/tools/BUILD.gn @@ -56,6 +56,19 @@ crashpad_executable("crashpad_http_upload") { ] } +crashpad_executable("base94_encoder") { + sources = [ + "base94_encoder.cc", + ] + deps = [ + ":tool_support", + "../build:default_exe_manifest_win", + "../third_party/mini_chromium:base", + "../third_party/zlib", + "../util", + ] +} + if (!crashpad_is_fuchsia) { crashpad_executable("generate_dump") { sources = [ diff --git a/tools/base94_encoder.cc b/tools/base94_encoder.cc new file mode 100644 index 00000000..d4789250 --- /dev/null +++ b/tools/base94_encoder.cc @@ -0,0 +1,128 @@ +// 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. + +#include <getopt.h> +#include <stdio.h> + +#include "base/files/file_path.h" +#include "build/build_config.h" +#include "tools/tool_support.h" +#include "util/stream/file_encoder.h" + +namespace crashpad { +namespace { + +void Usage(const base::FilePath& me) { + fprintf(stderr, +"Usage: %" PRFilePath " [options] <input-file> <output-file>\n" +"Encode/Decode the given file\n" +"\n" +" -e, --encode compress and encode the input file to a base94 encoded" + " file\n" +" -d, --decode decode and decompress a base94 encoded file\n" +" --help display this help and exit\n" +" --version output version information and exit\n", + me.value().c_str()); + ToolSupport::UsageTail(me); +} + +int Base94EncoderMain(int argc, char* argv[]) { + const base::FilePath argv0( + ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); + const base::FilePath me(argv0.BaseName()); + + enum OptionFlags { + // “Short” (single-character) options. + kOptionEncode = 'e', + kOptionDecode = 'd', + + // Standard options. + kOptionHelp = -2, + kOptionVersion = -3, + }; + + struct Options { + bool encoding; + base::FilePath input_file; + base::FilePath output_file; + } options = {}; + + static constexpr option long_options[] = { + {"encode", no_argument, nullptr, kOptionEncode}, + {"decode", no_argument, nullptr, kOptionDecode}, + {"help", no_argument, nullptr, kOptionHelp}, + {"version", no_argument, nullptr, kOptionVersion}, + {nullptr, 0, nullptr, 0}, + }; + + bool encoding_valid = false; + int opt; + while ((opt = getopt_long(argc, argv, "d:e", long_options, nullptr)) != -1) { + switch (opt) { + case kOptionEncode: + options.encoding = true; + encoding_valid = true; + break; + case kOptionDecode: + options.encoding = false; + encoding_valid = true; + break; + case kOptionHelp: + Usage(me); + return EXIT_SUCCESS; + case kOptionVersion: + ToolSupport::Version(me); + return EXIT_SUCCESS; + default: + ToolSupport::UsageHint(me, nullptr); + return EXIT_FAILURE; + } + } + + if (!encoding_valid) { + ToolSupport::UsageHint(me, "Either -e or -d required"); + return EXIT_FAILURE; + } + + argc -= optind; + argv += optind; + if (argc != 2) { + ToolSupport::UsageHint(me, "Both input-file and output-file required"); + return EXIT_FAILURE; + } + + options.input_file = base::FilePath( + ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); + options.output_file = base::FilePath( + ToolSupport::CommandLineArgumentToFilePathStringType(argv[1])); + + FileEncoder encoder(options.encoding ? crashpad::FileEncoder::Mode::kEncode + : crashpad::FileEncoder::Mode::kDecode, + options.input_file, + options.output_file); + return encoder.Process() ? EXIT_SUCCESS : EXIT_FAILURE; +} + +} // namespace +} // namespace crashpad + +#if defined(OS_POSIX) +int main(int argc, char* argv[]) { + return crashpad::Base94EncoderMain(argc, argv); +} +#elif defined(OS_WIN) +int wmain(int argc, wchar_t* argv[]) { + return crashpad::ToolSupport::Wmain(argc, argv, crashpad::Base94EncoderMain); +} +#endif // OS_POSIX diff --git a/util/BUILD.gn b/util/BUILD.gn index e24b675c..11d48445 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -168,6 +168,10 @@ static_library("util") { "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", @@ -593,6 +597,7 @@ source_set("util_test") { "stdlib/strnlen_test.cc", "stdlib/thread_safe_vector_test.cc", "stream/base94_output_stream_test.cc", + "stream/file_encoder_test.cc", "stream/log_output_stream_test.cc", "stream/test_output_stream.cc", "stream/test_output_stream.h", diff --git a/util/stream/file_encoder.cc b/util/stream/file_encoder.cc new file mode 100644 index 00000000..bb2c41a3 --- /dev/null +++ b/util/stream/file_encoder.cc @@ -0,0 +1,85 @@ +// 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. + +#include "util/stream/file_encoder.h" + +#include <memory> + +#include "base/logging.h" +#include "base/macros.h" +#include "util/file/file_io.h" +#include "util/file/file_reader.h" +#include "util/file/scoped_remove_file.h" +#include "util/stream/base94_output_stream.h" +#include "util/stream/file_output_stream.h" +#include "util/stream/output_stream_interface.h" +#include "util/stream/zlib_output_stream.h" + +namespace crashpad { + +FileEncoder::FileEncoder(Mode mode, + const base::FilePath& input_path, + const base::FilePath& output_path) + : mode_(mode), input_path_(input_path), output_path_(output_path) {} + +FileEncoder::~FileEncoder() {} + +bool FileEncoder::Process() { + ScopedRemoveFile file_remover; + ScopedFileHandle write_handle(LoggingOpenFileForWrite( + output_path_, FileWriteMode::kCreateOrFail, FilePermissions::kOwnerOnly)); + if (!write_handle.is_valid()) + return false; + + // Remove the output file on failure. + file_remover.reset(output_path_); + + std::unique_ptr<OutputStreamInterface> output; + if (mode_ == Mode::kEncode) { + output = std::make_unique<ZlibOutputStream>( + ZlibOutputStream::Mode::kCompress, + std::make_unique<Base94OutputStream>( + Base94OutputStream::Mode::kEncode, + std::make_unique<FileOutputStream>(write_handle.get()))); + } else { + output = std::make_unique<Base94OutputStream>( + Base94OutputStream::Mode::kDecode, + std::make_unique<ZlibOutputStream>( + ZlibOutputStream::Mode::kDecompress, + std::make_unique<FileOutputStream>(write_handle.get()))); + } + + FileReader file_reader; + if (!file_reader.Open(input_path_)) + return false; + + FileOperationResult read_result; + do { + uint8_t buffer[4096]; + read_result = file_reader.Read(buffer, sizeof(buffer)); + if (read_result < 0) + return false; + + if (read_result > 0 && (!output->Write(buffer, read_result))) + return false; + } while (read_result > 0); + + if (!output->Flush()) + return false; + + ignore_result(file_remover.release()); + return true; +} + +} // namespace crashpad diff --git a/util/stream/file_encoder.h b/util/stream/file_encoder.h new file mode 100644 index 00000000..2f34b0bf --- /dev/null +++ b/util/stream/file_encoder.h @@ -0,0 +1,59 @@ +// 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_UTIL_STREAM_FILE_ENCODER_H_ +#define CRASHPAD_UTIL_STREAM_FILE_ENCODER_H_ + +#include "base/files/file_path.h" +#include "base/macros.h" + +namespace crashpad { + +//! \brief The class is used to compress and base94-encode, or base94-decode +//! and decompress the given input file to the output file. +class FileEncoder { + public: + //! \brief Whether this object is configured to encode or decode data. + enum class Mode : bool { + //! \brief Data passed through this object is encoded. + kEncode = false, + //! \brief Data passed through this object is decoded. + kDecode = true + }; + + //! \param[in] mode The work mode of this object. + //! \param[in] input_path The input file that this object reads from. + //! \param[in] output_path The output file that this object writes to. + FileEncoder(Mode mode, + const base::FilePath& input_path, + const base::FilePath& output_path); + ~FileEncoder(); + + //! \brief Encode/decode the data from \a input_path_ file according work + //! \a mode, and write the result to \a output_path_ on success. + //! + //! \return `true` on success. + bool Process(); + + private: + Mode mode_; + base::FilePath input_path_; + base::FilePath output_path_; + + DISALLOW_COPY_AND_ASSIGN(FileEncoder); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_STREAM_FILE_ENCODER_H_ diff --git a/util/stream/file_encoder_test.cc b/util/stream/file_encoder_test.cc new file mode 100644 index 00000000..ff989146 --- /dev/null +++ b/util/stream/file_encoder_test.cc @@ -0,0 +1,112 @@ +// 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. + +#include "util/stream/file_encoder.h" + +#include <algorithm> +#include <memory> +#include <string> + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "gtest/gtest.h" +#include "test/scoped_temp_dir.h" +#include "util/file/file_io.h" +#include "util/stream/file_output_stream.h" + +namespace crashpad { +namespace test { +namespace { + +constexpr size_t kBufferSize = 4096; + +class FileEncoderTest : public testing::Test { + public: + FileEncoderTest() {} + + void Verify(size_t size) { + std::string contents; + ASSERT_TRUE(LoggingReadEntireFile(decoded_, &contents)); + ASSERT_EQ(contents.size(), size); + EXPECT_EQ(memcmp(deterministic_input_.get(), contents.data(), size), 0); + } + + const uint8_t* BuildDeterministicInput(size_t size) { + deterministic_input_ = std::make_unique<uint8_t[]>(size); + uint8_t* deterministic_input_base = deterministic_input_.get(); + while (size-- > 0) + deterministic_input_base[size] = static_cast<uint8_t>(size); + return deterministic_input_base; + } + + void GenerateOrigFile(size_t size) { + ScopedFileHandle write_handle(OpenFileForWrite( + orig_, FileWriteMode::kCreateOrFail, FilePermissions::kOwnerOnly)); + ASSERT_TRUE(write_handle.is_valid()); + FileOutputStream out(write_handle.get()); + const uint8_t* buf = BuildDeterministicInput(size); + while (size > 0) { + size_t m = std::min(kBufferSize, size); + ASSERT_TRUE(out.Write(buf, m)); + size -= m; + buf += m; + } + ASSERT_TRUE(out.Flush()); + } + + FileEncoder* encoder() const { return encoder_.get(); } + + FileEncoder* decoder() const { return decoder_.get(); } + + protected: + void SetUp() override { + temp_dir_ = std::make_unique<ScopedTempDir>(); + orig_ = base::FilePath(temp_dir_->path().Append(FILE_PATH_LITERAL("orig"))); + encoded_ = + base::FilePath(temp_dir_->path().Append(FILE_PATH_LITERAL("encoded"))); + decoded_ = + base::FilePath(temp_dir_->path().Append(FILE_PATH_LITERAL("decoded"))); + encoder_ = std::make_unique<FileEncoder>( + FileEncoder::Mode::kEncode, orig_, encoded_); + decoder_ = std::make_unique<FileEncoder>( + FileEncoder::Mode::kDecode, encoded_, decoded_); + } + + private: + std::unique_ptr<ScopedTempDir> temp_dir_; + base::FilePath orig_; + base::FilePath encoded_; + base::FilePath decoded_; + std::unique_ptr<FileEncoder> encoder_; + std::unique_ptr<FileEncoder> decoder_; + std::unique_ptr<uint8_t[]> deterministic_input_; +}; + +TEST_F(FileEncoderTest, ProcessShortFile) { + GenerateOrigFile(kBufferSize - 512); + EXPECT_TRUE(encoder()->Process()); + EXPECT_TRUE(decoder()->Process()); + Verify(kBufferSize - 512); +} + +TEST_F(FileEncoderTest, ProcessLongFile) { + GenerateOrigFile(kBufferSize + 512); + EXPECT_TRUE(encoder()->Process()); + EXPECT_TRUE(decoder()->Process()); + Verify(kBufferSize + 512); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/stream/file_output_stream.cc b/util/stream/file_output_stream.cc new file mode 100644 index 00000000..022d91fe --- /dev/null +++ b/util/stream/file_output_stream.cc @@ -0,0 +1,45 @@ +// 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. + +#include "util/stream/file_output_stream.h" + +#include "base/logging.h" + +namespace crashpad { + +FileOutputStream::FileOutputStream(FileHandle file_handle) + : writer_(file_handle), flush_needed_(false), flushed_(false) {} + +FileOutputStream::~FileOutputStream() { + DCHECK(!flush_needed_); +} + +bool FileOutputStream::Write(const uint8_t* data, size_t size) { + DCHECK(!flushed_); + + if (!writer_.Write(data, size)) { + LOG(ERROR) << "Write: Failed"; + return false; + } + flush_needed_ = true; + return true; +} + +bool FileOutputStream::Flush() { + flush_needed_ = false; + flushed_ = true; + return true; +} + +} // namespace crashpad diff --git a/util/stream/file_output_stream.h b/util/stream/file_output_stream.h new file mode 100644 index 00000000..128ccd5e --- /dev/null +++ b/util/stream/file_output_stream.h @@ -0,0 +1,46 @@ +// 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_UTIL_STREAM_FILE_OUTPUT_STREAM_H_ +#define CRASHPAD_UTIL_STREAM_FILE_OUTPUT_STREAM_H_ + +#include "base/macros.h" +#include "util/file/file_io.h" +#include "util/file/file_writer.h" +#include "util/stream/output_stream_interface.h" + +namespace crashpad { + +//! \brief The class is used to write data to a file. +class FileOutputStream : public OutputStreamInterface { + public: + //! \param[in] file_handle The file that this object writes to. + explicit FileOutputStream(FileHandle file_handle); + ~FileOutputStream(); + + // OutputStream. + bool Write(const uint8_t* data, size_t size) override; + bool Flush() override; + + private: + WeakFileHandleFileWriter writer_; + bool flush_needed_; + bool flushed_; + + DISALLOW_COPY_AND_ASSIGN(FileOutputStream); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_STREAM_FILE_OUTPUT_STREAM_H_ From 38f4bae3ad841821a83abe979892cbcab69e2e02 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Thu, 19 Dec 2019 12:09:25 -0800 Subject: [PATCH 308/401] chromeos: fix minidump-dir-for-tests flag Bug: b/145241430 Change-Id: I766c9bcb6f0b2eaf4219dad38cdb02867bf76a2b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1976077 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- handler/handler_main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 7d9701c0..80babc31 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -632,7 +632,7 @@ int HandlerMain(int argc, no_argument, nullptr, kOptionUseCrosCrashReporter}, - {"minidump_dir_for_tests", + {"minidump-dir-for-tests", required_argument, nullptr, kOptionMinidumpDirForTests}, From c2978022d17854550e5b83d98c425027f31c22a1 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich <vtsyrklevich@chromium.org> Date: Thu, 19 Dec 2019 16:41:57 -0800 Subject: [PATCH 309/401] Update comment to match current state of MemorySnapshotGeneric MemorySnapshotGeneric is now used on all platforms as it uses ProcessMemory instead of templating to use a platform-specific ProcessReader* class. Change-Id: Ib0b6db0fac184c558f1c76a584db92e4804dfe99 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1977640 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vlad Tsyrklevich <vtsyrklevich@chromium.org> --- snapshot/memory_snapshot_generic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snapshot/memory_snapshot_generic.h b/snapshot/memory_snapshot_generic.h index 1a74d4e4..d8bc9ec7 100644 --- a/snapshot/memory_snapshot_generic.h +++ b/snapshot/memory_snapshot_generic.h @@ -29,8 +29,8 @@ namespace crashpad { namespace internal { //! \brief A MemorySnapshot of a memory region in a process on the running -//! system. Used on Mac, Linux, Android, and Fuchsia, templated on the -//! platform-specific ProcessReader type. +//! system. Works on multiple platforms by using a platform-specific +//! ProcessMemory object. class MemorySnapshotGeneric final : public MemorySnapshot { public: MemorySnapshotGeneric() = default; From 558b7ea43ff5c9ccda03ce946364cdff15401575 Mon Sep 17 00:00:00 2001 From: Ian Barkley-Yeung <iby@chromium.org> Date: Mon, 23 Dec 2019 16:19:07 -0800 Subject: [PATCH 310/401] Pass --always_allow_feedback during integration tests During ChromeOS integration tests, pass --always_allow_feedback to crash_reporter. Most integration tests do not set metrics consent but still want crash dumps. Needs https://chromium-review.googlesource.com/c/chromium/src/+/1981139 as well BUG=chromium:1037656 TEST=tast -verbose run --extrauseflags chrome_internal my_crbook ui.ChromeCrashNotLoggedInDirect Change-Id: Ibc7af4b31da789c52aec6e668a4b192d4e20fdfc Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1981037 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Ian Barkley-Yeung <iby@chromium.org> --- handler/handler_main.cc | 20 ++++++++++++++++++- .../cros_crash_report_exception_handler.cc | 6 +++++- .../cros_crash_report_exception_handler.h | 2 ++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 80babc31..1cf655ae 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -168,6 +168,10 @@ void Usage(const base::FilePath& me) { " --minidump-dir-for-tests=TEST_MINIDUMP_DIR\n" " causes /sbin/crash_reporter to leave dumps in\n" " this directory instead of the normal location\n" +" --always-allow-feedback\n" +" pass the --always_allow_feedback flag to\n" +" crash_reporter, thus skipping metrics consent\n" +" checks\n" #endif // OS_CHROMEOS " --help display this help and exit\n" " --version output version information and exit\n", @@ -201,8 +205,9 @@ struct Options { bool rate_limit; bool upload_gzip; #if defined(OS_CHROMEOS) - bool use_cros_crash_reporter; + bool use_cros_crash_reporter = false; base::FilePath minidump_dir_for_tests; + bool always_allow_feedback = false; #endif // OS_CHROMEOS }; @@ -561,6 +566,7 @@ int HandlerMain(int argc, #if defined(OS_CHROMEOS) kOptionUseCrosCrashReporter, kOptionMinidumpDirForTests, + kOptionAlwaysAllowFeedback, #endif // OS_CHROMEOS // Standard options. @@ -636,6 +642,10 @@ int HandlerMain(int argc, required_argument, nullptr, kOptionMinidumpDirForTests}, + {"always-allow-feedback", + no_argument, + nullptr, + kOptionAlwaysAllowFeedback}, #endif // OS_CHROMEOS {"help", no_argument, nullptr, kOptionHelp}, {"version", no_argument, nullptr, kOptionVersion}, @@ -788,6 +798,10 @@ int HandlerMain(int argc, ToolSupport::CommandLineArgumentToFilePathStringType(optarg)); break; } + case kOptionAlwaysAllowFeedback: { + options.always_allow_feedback = true; + break; + } #endif // OS_CHROMEOS case kOptionHelp: { Usage(me); @@ -931,6 +945,10 @@ int HandlerMain(int argc, cros_handler->SetDumpDir(options.minidump_dir_for_tests); } + if (options.always_allow_feedback) { + cros_handler->SetAlwaysAllowFeedback(); + } + exception_handler = std::move(cros_handler); } else { exception_handler = std::make_unique<CrashReportExceptionHandler>( diff --git a/handler/linux/cros_crash_report_exception_handler.cc b/handler/linux/cros_crash_report_exception_handler.cc index f54cc07c..b394d61f 100644 --- a/handler/linux/cros_crash_report_exception_handler.cc +++ b/handler/linux/cros_crash_report_exception_handler.cc @@ -133,7 +133,8 @@ CrosCrashReportExceptionHandler::CrosCrashReportExceptionHandler( const UserStreamDataSources* user_stream_data_sources) : database_(database), process_annotations_(process_annotations), - user_stream_data_sources_(user_stream_data_sources) {} + user_stream_data_sources_(user_stream_data_sources), + always_allow_feedback_(false) {} CrosCrashReportExceptionHandler::~CrosCrashReportExceptionHandler() = default; @@ -258,6 +259,9 @@ bool CrosCrashReportExceptionHandler::HandleExceptionWithConnection( if (!dump_dir_.empty()) { argv.push_back("--chrome_dump_dir=" + dump_dir_.value()); } + if (always_allow_feedback_) { + argv.push_back("--always_allow_feedback"); + } if (!DoubleForkAndExec(argv, nullptr /* envp */, diff --git a/handler/linux/cros_crash_report_exception_handler.h b/handler/linux/cros_crash_report_exception_handler.h index def1c82b..0b145448 100644 --- a/handler/linux/cros_crash_report_exception_handler.h +++ b/handler/linux/cros_crash_report_exception_handler.h @@ -77,6 +77,7 @@ class CrosCrashReportExceptionHandler UUID* local_report_id = nullptr) override; void SetDumpDir(const base::FilePath& dump_dir) { dump_dir_ = dump_dir; } + void SetAlwaysAllowFeedback() { always_allow_feedback_ = true; } private: bool HandleExceptionWithConnection( PtraceConnection* connection, @@ -90,6 +91,7 @@ class CrosCrashReportExceptionHandler const std::map<std::string, std::string>* process_annotations_; // weak const UserStreamDataSources* user_stream_data_sources_; // weak base::FilePath dump_dir_; + bool always_allow_feedback_; DISALLOW_COPY_AND_ASSIGN(CrosCrashReportExceptionHandler); }; From 54bbd7d0d583de565b2f5d1719d5706d722c9b66 Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Tue, 7 Jan 2020 11:14:27 -0500 Subject: [PATCH 311/401] Adds support for running GTests on iOS. iOS needs to run tests from within the context of a UIApplication, and it needs to periodically spin the runloop to ensure that the watchdog does not kill the app for being unresponsive. BUG=crashpad:31 Change-Id: Ia1d881e478d4f83c236b475a21529760c06100c7 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1904226 Commit-Queue: Rohit Rao <rohitrao@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- build/ios/Default.png | Bin 0 -> 1707 bytes build/ios/Unittest-Info.plist | 10 +++ build/test.gni | 32 +++++++++- test/BUILD.gn | 21 +++++++ test/gtest_main.cc | 11 ++++ test/gtest_runner_ios.h | 33 ++++++++++ test/gtest_runner_ios.mm | 114 ++++++++++++++++++++++++++++++++++ 7 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 build/ios/Default.png create mode 100644 build/ios/Unittest-Info.plist create mode 100644 test/gtest_runner_ios.h create mode 100644 test/gtest_runner_ios.mm diff --git a/build/ios/Default.png b/build/ios/Default.png new file mode 100644 index 0000000000000000000000000000000000000000..8c9089d5c6789aae633902ca93ad552f14bfadd7 GIT binary patch literal 1707 zcmdT^J!sQ$5PkW8epw_Ss70g%1t+PTIEWyT1Py4dZ6iWKT5V1oN>mC_5D67aT-<N# z;FLif#12_%9YpwTE>a0POUYLJLVmvcLvhefUF=P{-`%}?@7<p~9veM7*gw<{V6c3y zI1Z#6K=xK|21uQ}eE2B~`{zqn<|k@8U!S>CMPasftvXzuo4HXPug=WgyZx?u3dmsW z{A4M5gcvPGjZtERXCcI3F=z}D1H5P<nnlxS5)Iy~A*w~ys1g-EDj|wR(I^rHM2ZLz z7NHRm!Gzd^CKiX;4d3HoA!rB^0(>nqvtSxbg27p^s1{U%N>Df{_KF43AQA-R$k6}` z&;SYGR<b4-Ns}dMvBt&3CN!})3>V}%L(Rktu8(V(shWx@TrOF#C~6`mpn8&GuR#rB zpgj6Pnw+K`)K3yrNY(@+X|iN1d2lhY2~8}xb6#f75LLL5)W@~VL{vauDVHo*REUB; z(rFq%UTmk)R7)%A2WfJec90VVQz2OsjHEe9TI9jS#3nTSMBdFZa|U=Z8cBUz%S`wg zC0~QfO%BY9`aP2)IjO{VKW}2Cb4=XvYbS!8a-zYHpU`pz$tFS*i&vs~)YJt!KpSWQ zO`r}`fFh6wa-^}1a<|*<bUN*JyVYtno6UN?Ua3@y#bQ36&*dEZXYT?@WD4bCVe;<U z`s-sUKCUipT$~%+y~LlJaqt3CA0AyF^1SeCYU)j9akB)hOr&27yglv@3qO`$E%xkk zl)s{}oSokL<fgx8H)?Y|wSDQodbWPJ-?wt~z<aOve)+Vv=fOyJ>)vfuz8z{{eKplb zkj7Gc{xNsN|7&(qtXxXJ{Bw^J4^RL59y>|Wf6n#u!0=b3O5d-JIMH%xwD|1I^uljm C#i;ZE literal 0 HcmV?d00001 diff --git a/build/ios/Unittest-Info.plist b/build/ios/Unittest-Info.plist new file mode 100644 index 00000000..9256fb44 --- /dev/null +++ b/build/ios/Unittest-Info.plist @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleIdentifier</key> + <string>${IOS_BUNDLE_ID_PREFIX}.gtest.${GTEST_BUNDLE_ID_SUFFIX:rfc1034identifier}</string> + <key>UIApplicationDelegate</key> + <string>CrashpadUnitTestDelegate</string> +</dict> +</plist> diff --git a/build/test.gni b/build/test.gni index f46520b7..24c343d7 100644 --- a/build/test.gni +++ b/build/test.gni @@ -18,9 +18,35 @@ if (crashpad_is_in_chromium) { import("//testing/test.gni") } else { template("test") { - executable(target_name) { - testonly = true - forward_variables_from(invoker, "*") + if (crashpad_is_ios) { + import("//third_party/mini_chromium/mini_chromium/build/ios/rules.gni") + + _launch_image_bundle_target = target_name + "_launch_image" + bundle_data(_launch_image_bundle_target) { + forward_variables_from(invoker, [ "testonly" ]) + sources = [ + "//build/ios/Default.png", + ] + outputs = [ + "{{bundle_contents_dir}}/{{source_file_part}}", + ] + } + + ios_app_bundle(target_name) { + testonly = true + info_plist = "//build/ios/Unittest-Info.plist" + extra_substitutions = [ "GTEST_BUNDLE_ID_SUFFIX=$target_name" ] + forward_variables_from(invoker, "*") + if (!defined(deps)) { + deps = [] + } + deps += [ ":$_launch_image_bundle_target" ] + } + } else { + executable(target_name) { + testonly = true + forward_variables_from(invoker, "*") + } } } } diff --git a/test/BUILD.gn b/test/BUILD.gn index 5159744b..f9c81324 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -243,6 +243,21 @@ if (!crashpad_is_ios) { } } +if (crashpad_is_ios) { + source_set("test_runner_ios") { + testonly = true + sources = [ + "gtest_runner_ios.h", + "gtest_runner_ios.mm", + ] + configs += [ "..:crashpad_config" ] + deps = [ + "../third_party/gtest:gtest", + ] + libs = [ "UIKit.framework" ] + } +} + static_library("gmock_main") { testonly = true sources = [ @@ -257,6 +272,9 @@ static_library("gmock_main") { "../third_party/mini_chromium:base", "../third_party/mini_chromium:base_test_support", ] + if (crashpad_is_ios) { + deps += [ ":test_runner_ios" ] + } } static_library("gtest_main") { @@ -272,4 +290,7 @@ static_library("gtest_main") { "../third_party/mini_chromium:base", "../third_party/mini_chromium:base_test_support", ] + if (crashpad_is_ios) { + deps += [ ":test_runner_ios" ] + } } diff --git a/test/gtest_main.cc b/test/gtest_main.cc index 0a7a2d3a..f6b6a69e 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -21,6 +21,10 @@ #include "gmock/gmock.h" #endif // CRASHPAD_TEST_LAUNCHER_GMOCK +#if defined(OS_IOS) +#include "test/gtest_runner_ios.h" +#endif + #if defined(OS_WIN) #include "test/win/win_child_process.h" #endif // OS_WIN @@ -93,5 +97,12 @@ int main(int argc, char* argv[]) { #error #define CRASHPAD_TEST_LAUNCHER_GTEST or CRASHPAD_TEST_LAUNCHER_GMOCK #endif // CRASHPAD_TEST_LAUNCHER_GMOCK +#if defined(OS_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. + crashpad::test::IOSLaunchApplicationAndRunTests(argc, argv); +#else return RUN_ALL_TESTS(); +#endif } diff --git a/test/gtest_runner_ios.h b/test/gtest_runner_ios.h new file mode 100644 index 00000000..564fe5c2 --- /dev/null +++ b/test/gtest_runner_ios.h @@ -0,0 +1,33 @@ +// 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_TEST_GTEST_RUNNER_IOS_ +#define CRASHPAD_TEST_GTEST_RUNNER_IOS_ + +namespace crashpad { +namespace test { + +//! \brief Runs all registered tests in the context of a UIKit application. +//! +//! Invokes UIApplicationMain() to launch the iOS application and runs all +//! registered tests after the application finishes +//! launching. UIApplicationMain() brings up the main runloop and never returns, +//! so therefore this function never returns either. It invokes _exit() to +//! terminate the application after tests have completed. +void IOSLaunchApplicationAndRunTests(int argc, char* argv[]); + +} // namespace test +} // namespace crashpad + +#endif // CRASHPAD_TEST_GTEST_RUNNER_IOS_ diff --git a/test/gtest_runner_ios.mm b/test/gtest_runner_ios.mm new file mode 100644 index 00000000..8738fcb9 --- /dev/null +++ b/test/gtest_runner_ios.mm @@ -0,0 +1,114 @@ +// 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. + +#include "test/gtest_runner_ios.h" + +#import <UIKit/UIKit.h> + +#include "gtest/gtest.h" + +@interface UIApplication (Testing) +- (void)_terminateWithStatus:(int)status; +@end + +namespace { + +// The iOS watchdog timer will kill an app that doesn't spin the main event +// loop often enough. This uses a Gtest TestEventListener to spin the current +// loop after each test finishes. However, if any individual test takes too +// long, it is still possible that the app will get killed. +class IOSRunLoopListener : public testing::EmptyTestEventListener { + public: + virtual void OnTestEnd(const testing::TestInfo& test_info) { + @autoreleasepool { + // At the end of the test, spin the default loop for a moment. + NSDate* stop_date = [NSDate dateWithTimeIntervalSinceNow:0.001]; + [[NSRunLoop currentRunLoop] runUntilDate:stop_date]; + } + } +}; + +void RegisterTestEndListener() { + testing::TestEventListeners& listeners = + testing::UnitTest::GetInstance()->listeners(); + listeners.Append(new IOSRunLoopListener); +} + +} // namespace + +@interface CrashpadUnitTestDelegate : NSObject +@property(nonatomic, readwrite, strong) UIWindow* window; +- (void)runTests; +@end + +@implementation CrashpadUnitTestDelegate + +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; + self.window.backgroundColor = UIColor.whiteColor; + [self.window makeKeyAndVisible]; + + UIViewController* controller = [[UIViewController alloc] init]; + [self.window setRootViewController:controller]; + + // Add a label with the app name. + UILabel* label = [[UILabel alloc] initWithFrame:controller.view.bounds]; + label.text = [[NSProcessInfo processInfo] processName]; + label.textAlignment = NSTextAlignmentCenter; + label.textColor = UIColor.blackColor; + [controller.view addSubview:label]; + + // Queue up the test run. + [self performSelector:@selector(runTests) withObject:nil afterDelay:0.1]; + + return YES; +} + +- (void)runTests { + RegisterTestEndListener(); + + int exitStatus = RUN_ALL_TESTS(); + + // If a test app is too fast, it will exit before Instruments has has a + // a chance to initialize and no test results will be seen. + // TODO(crbug.com/137010): Figure out how much time is actually needed, and + // sleep only to make sure that much time has elapsed since launch. + [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]]; + self.window = nil; + + // Use the hidden selector to try and cleanly take down the app (otherwise + // things can think the app crashed even on a zero exit status). + UIApplication* application = [UIApplication sharedApplication]; + [application _terminateWithStatus:exitStatus]; + + exit(exitStatus); +} + +@end + + +namespace crashpad { +namespace test { + +void IOSLaunchApplicationAndRunTests(int argc, char* argv[]) { + @autoreleasepool { + int exit_status = + UIApplicationMain(argc, argv, nil, @"CrashpadUnitTestDelegate"); + exit(exit_status); + } +} + +} // namespace crashpad +} // namespace test From 0b8741b0740e59137e091e851d28167b91ef92b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=9Aniatowski?= <tsniatowski@vewd.com> Date: Mon, 13 Jan 2020 09:44:31 +0100 Subject: [PATCH 312/401] Remove redundant semicolon in cpu_context_linux.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a -Wextra-semi warning in Clang when building crashpad for MIPS. Change-Id: I53893c815de74d2503acdce24708e29096f4b0aa Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1997103 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Tomasz Śniatowski <tsniatowski@vewd.com> --- snapshot/linux/cpu_context_linux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapshot/linux/cpu_context_linux.h b/snapshot/linux/cpu_context_linux.h index 37fbc432..9f46a489 100644 --- a/snapshot/linux/cpu_context_linux.h +++ b/snapshot/linux/cpu_context_linux.h @@ -170,7 +170,7 @@ void InitializeCPUContextMIPS( memcpy(&context->fpregs, &float_context.fpregs, sizeof(context->fpregs)); context->fpcsr = float_context.fpcsr; context->fir = float_context.fpu_id; -}; +} #endif // ARCH_CPU_MIPS_FAMILY || DOXYGEN From 4367e9df172c579ca232ef98d76b1a00d7333e8a Mon Sep 17 00:00:00 2001 From: Vitaly Buka <vitalybuka@chromium.org> Date: Fri, 10 Jan 2020 16:26:53 -0800 Subject: [PATCH 313/401] Increase kAllowedOffset for non-optimized build "init_stack_vars = true" inserts additional instructions which usually removed by optimization if code does not rely on undefined behaviour of uninitialized variables. However in non-optimized build these instructions may still be present. Fixing https://ci.chromium.org/p/chromium/builders/ci/Win10%20Tests%20x64%20%28dbg%29/12597 Related patch: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1949846 Bug: chromium:1030261 Change-Id: Ib05fa8580d4b0206f70e2dfac5e0f3a3d4389f95 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1995823 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Vitaly Buka <vitalybuka@chromium.org> --- snapshot/win/exception_snapshot_win_test.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index 2d4e9090..07a25a89 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -102,7 +102,12 @@ class CrashingDelegate : public ExceptionHandlerServer::Delegate { // Verify the exception happened at the expected location with a bit of // slop space to allow for reading the current PC before the exception // happens. See TestCrashingChild(). +#if !defined(NDEBUG) + // Debug build is likely not optimized and contains more instructions. + constexpr uint64_t kAllowedOffset = 200; +#else constexpr uint64_t kAllowedOffset = 100; +#endif EXPECT_GT(snapshot.Exception()->ExceptionAddress(), break_near_); EXPECT_LT(snapshot.Exception()->ExceptionAddress(), break_near_ + kAllowedOffset); @@ -215,7 +220,7 @@ class SimulateDelegate : public ExceptionHandlerServer::Delegate { constexpr uint64_t kAllowedOffset = 500; #elif !defined(NDEBUG) // Debug build is likely not optimized and contains more instructions. - constexpr uint64_t kAllowedOffset = 150; + constexpr uint64_t kAllowedOffset = 200; #else constexpr uint64_t kAllowedOffset = 100; #endif From 2fd16e33929465469749d0abb96ea70902da595f Mon Sep 17 00:00:00 2001 From: Nico Weber <thakis@chromium.org> Date: Thu, 23 Jan 2020 08:00:33 -0500 Subject: [PATCH 314/401] Reformat all gn files Port of chromium-side https://chromium-review.googlesource.com/c/chromium/src/+/1997899 Bug: chromium:1041419 Change-Id: Ic7afefa0dea024da37fe4bb0f965840a160e2166 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2015428 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- BUILD.gn | 4 +- build/BUILD.gn | 4 +- build/test.gni | 8 +-- client/BUILD.gn | 12 +--- handler/BUILD.gn | 84 ++++++----------------- minidump/BUILD.gn | 12 +--- snapshot/BUILD.gn | 56 ++++------------ test/BUILD.gn | 32 +++------ third_party/apple_cf/BUILD.gn | 4 +- third_party/cpp-httplib/BUILD.gn | 4 +- third_party/fuchsia/BUILD.gn | 12 +--- third_party/glibc/BUILD.gn | 4 +- third_party/gtest/BUILD.gn | 104 ++++++++--------------------- third_party/lss/BUILD.gn | 4 +- third_party/mini_chromium/BUILD.gn | 16 ++--- third_party/xnu/BUILD.gn | 4 +- third_party/zlib/BUILD.gn | 4 +- tools/BUILD.gn | 44 +++--------- util/BUILD.gn | 32 +++------ 19 files changed, 111 insertions(+), 333 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index b1294cfb..f47c6aa2 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -121,9 +121,7 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { } package("crashpad_database_util") { - deps = [ - "tools:crashpad_database_util", - ] + deps = [ "tools:crashpad_database_util" ] binaries = [ { diff --git a/build/BUILD.gn b/build/BUILD.gn index bc77bc81..6e6ccd64 100644 --- a/build/BUILD.gn +++ b/build/BUILD.gn @@ -32,9 +32,7 @@ config("crashpad_is_in_fuchsia") { group("default_exe_manifest_win") { if (crashpad_is_in_chromium) { - deps = [ - "//build/win:default_exe_manifest", - ] + deps = [ "//build/win:default_exe_manifest" ] } } diff --git a/build/test.gni b/build/test.gni index 24c343d7..867b7730 100644 --- a/build/test.gni +++ b/build/test.gni @@ -24,12 +24,8 @@ if (crashpad_is_in_chromium) { _launch_image_bundle_target = target_name + "_launch_image" bundle_data(_launch_image_bundle_target) { forward_variables_from(invoker, [ "testonly" ]) - sources = [ - "//build/ios/Default.png", - ] - outputs = [ - "{{bundle_contents_dir}}/{{source_file_part}}", - ] + sources = [ "//build/ios/Default.png" ] + outputs = [ "{{bundle_contents_dir}}/{{source_file_part}}" ] } ios_app_bundle(target_name) { diff --git a/client/BUILD.gn b/client/BUILD.gn index bfe03320..a61c66d0 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -90,15 +90,11 @@ static_library("client") { } if (crashpad_is_linux || crashpad_is_android) { - deps += [ - "../third_party/lss", - ] + deps += [ "../third_party/lss" ] } if (crashpad_is_fuchsia) { - deps += [ - "../third_party/fuchsia", - ] + deps += [ "../third_party/fuchsia" ] if (crashpad_is_in_fuchsia) { deps += [ "//zircon/public/lib/fdio" ] } @@ -141,9 +137,7 @@ source_set("client_test") { "../util", ] - data_deps = [ - "../handler:crashpad_handler", - ] + data_deps = [ "../handler:crashpad_handler" ] if (crashpad_is_win) { data_deps += [ "../handler:crashpad_handler_console" ] diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 6df147a8..8862faba 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -101,22 +101,16 @@ if (crashpad_is_android) { # CrashpadHandlerMain is defined in a separate target so that it can be # overriden by implementers source_set("crashpad_handler_main") { - sources = [ - "crashpad_handler_main.cc", - ] + sources = [ "crashpad_handler_main.cc" ] - deps = [ - ":handler", - ] + deps = [ ":handler" ] } } source_set("handler_test") { testonly = true - sources = [ - "minidump_to_upload_parameters_test.cc", - ] + sources = [ "minidump_to_upload_parameters_test.cc" ] if (crashpad_is_linux || crashpad_is_android) { sources += [ "linux/exception_handler_server_test.cc" ] @@ -147,9 +141,7 @@ source_set("handler_test") { } crashpad_executable("crashpad_handler") { - sources = [ - "main.cc", - ] + sources = [ "main.cc" ] deps = [ ":handler", @@ -177,26 +169,18 @@ crashpad_executable("crashpad_handler") { # handler executable an acceptable name. if (crashpad_is_android) { copy("crashpad_handler_named_as_so") { - deps = [ - ":crashpad_handler", - ] + deps = [ ":crashpad_handler" ] - sources = [ - "$root_out_dir/crashpad_handler", - ] + sources = [ "$root_out_dir/crashpad_handler" ] - outputs = [ - "$root_out_dir/libcrashpad_handler.so", - ] + outputs = [ "$root_out_dir/libcrashpad_handler.so" ] } crashpad_executable("crashpad_handler_trampoline") { set_sources_assignment_filter([]) output_name = "libcrashpad_handler_trampoline.so" - sources = [ - "linux/handler_trampoline.cc", - ] + sources = [ "linux/handler_trampoline.cc" ] ldflags = [ "-llog" ] @@ -209,9 +193,7 @@ if (crashpad_is_android) { crashpad_executable("crashpad_handler_test_extended_handler") { testonly = true - sources = [ - "crashpad_handler_test_extended_handler.cc", - ] + sources = [ "crashpad_handler_test_extended_handler.cc" ] deps = [ ":handler", @@ -225,9 +207,7 @@ crashpad_executable("crashpad_handler_test_extended_handler") { if (crashpad_is_win) { crashpad_executable("crashpad_handler_com") { - sources = [ - "main.cc", - ] + sources = [ "main.cc" ] # Avoid .exp, .ilk, and .lib file collisions with crashpad_handler.exe by # having this target produce crashpad_handler_com.com. Don’t use this target @@ -243,23 +223,15 @@ if (crashpad_is_win) { } copy("crashpad_handler_console") { - deps = [ - ":crashpad_handler_com", - ] - sources = [ - "$root_out_dir/crashpad_handler_com.com", - ] - outputs = [ - "$root_out_dir/crashpad_handler.com", - ] + deps = [ ":crashpad_handler_com" ] + sources = [ "$root_out_dir/crashpad_handler_com.com" ] + outputs = [ "$root_out_dir/crashpad_handler.com" ] } crashpad_executable("crash_other_program") { testonly = true - sources = [ - "win/crash_other_program.cc", - ] + sources = [ "win/crash_other_program.cc" ] deps = [ "../client", @@ -272,9 +244,7 @@ if (crashpad_is_win) { crashpad_executable("crashy_program") { testonly = true - sources = [ - "win/crashy_test_program.cc", - ] + sources = [ "win/crashy_test_program.cc" ] deps = [ "../client", @@ -285,9 +255,7 @@ if (crashpad_is_win) { crashpad_executable("crashy_signal") { testonly = true - sources = [ - "win/crashy_signal.cc", - ] + sources = [ "win/crashy_signal.cc" ] cflags = [ "/wd4702" ] # Unreachable code. @@ -300,17 +268,13 @@ if (crashpad_is_win) { crashpad_executable("fake_handler_that_crashes_at_startup") { testonly = true - sources = [ - "win/fake_handler_that_crashes_at_startup.cc", - ] + sources = [ "win/fake_handler_that_crashes_at_startup.cc" ] } crashpad_executable("hanging_program") { testonly = true - sources = [ - "win/hanging_program.cc", - ] + sources = [ "win/hanging_program.cc" ] deps = [ "../client", @@ -321,17 +285,13 @@ if (crashpad_is_win) { crashpad_loadable_module("loader_lock_dll") { testonly = true - sources = [ - "win/loader_lock_dll.cc", - ] + sources = [ "win/loader_lock_dll.cc" ] } crashpad_executable("self_destroying_program") { testonly = true - sources = [ - "win/self_destroying_test_program.cc", - ] + sources = [ "win/self_destroying_test_program.cc" ] deps = [ "../client", @@ -346,9 +306,7 @@ if (crashpad_is_win) { crashpad_executable("crashy_z7_loader") { testonly = true - sources = [ - "win/crashy_test_z7_loader.cc", - ] + sources = [ "win/crashy_test_z7_loader.cc" ] deps = [ "../client", diff --git a/minidump/BUILD.gn b/minidump/BUILD.gn index 86966d82..eb9f780d 100644 --- a/minidump/BUILD.gn +++ b/minidump/BUILD.gn @@ -71,9 +71,7 @@ static_library("minidump") { public_configs = [ "..:crashpad_config" ] - public_deps = [ - "../compat", - ] + public_deps = [ "../compat" ] deps = [ "../snapshot", @@ -113,9 +111,7 @@ static_library("test_support") { public_configs = [ "..:crashpad_config" ] - public_deps = [ - ":minidump", - ] + public_deps = [ ":minidump" ] deps = [ "../third_party/gtest:gtest", @@ -154,9 +150,7 @@ source_set("minidump_test") { "minidump_writable_test.cc", ] - configs += [ - "../build:crashpad_is_in_fuchsia", - ] + configs += [ "../build:crashpad_is_in_fuchsia" ] deps = [ ":test_support", diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 1be71f39..150b8017 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -238,9 +238,7 @@ static_library("snapshot") { if (crashpad_is_linux) { crashpad_fuzzer_test("elf_image_reader_fuzzer") { - sources = [ - "elf/elf_image_reader_fuzzer.cc", - ] + sources = [ "elf/elf_image_reader_fuzzer.cc" ] deps = [ ":snapshot", @@ -274,9 +272,7 @@ static_library("test_support") { public_configs = [ "..:crashpad_config" ] - public_deps = [ - ":snapshot", - ] + public_deps = [ ":snapshot" ] deps = [ "../compat", @@ -295,9 +291,7 @@ config("snapshot_test_link") { # There’s no way to make the link depend on this file. “inputs” doesn’t have # the intended effect in a config. https://crbug.com/781858, # https://crbug.com/796187. - inputs = [ - "elf/test_exported_symbols.sym", - ] + inputs = [ "elf/test_exported_symbols.sym" ] ldflags = [ "-Wl,--dynamic-list," + rebase_path(inputs[0], root_build_dir) ] } } @@ -431,9 +425,7 @@ source_set("snapshot_test") { crashpad_loadable_module("crashpad_snapshot_test_module") { testonly = true - sources = [ - "crashpad_info_client_options_test_module.cc", - ] + sources = [ "crashpad_info_client_options_test_module.cc" ] deps = [ "../client", "../third_party/mini_chromium:base", @@ -442,9 +434,7 @@ crashpad_loadable_module("crashpad_snapshot_test_module") { crashpad_loadable_module("crashpad_snapshot_test_module_large") { testonly = true - sources = [ - "crashpad_info_size_test_module.cc", - ] + sources = [ "crashpad_info_size_test_module.cc" ] deps = [] if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) { @@ -458,9 +448,7 @@ crashpad_loadable_module("crashpad_snapshot_test_module_large") { crashpad_loadable_module("crashpad_snapshot_test_module_small") { testonly = true - sources = [ - "crashpad_info_size_test_module.cc", - ] + sources = [ "crashpad_info_size_test_module.cc" ] deps = [] if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) { @@ -476,9 +464,7 @@ if ((crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) && target_cpu != "mipsel" && target_cpu != "mips64el") { crashpad_loadable_module("crashpad_snapshot_test_both_dt_hash_styles") { testonly = true - sources = [ - "hash_types_test.cc", - ] + sources = [ "hash_types_test.cc" ] # This makes `ld` emit both .hash and .gnu.hash sections. ldflags = [ "-Wl,--hash-style=both" ] @@ -495,18 +481,14 @@ if (crashpad_is_mac) { crashpad_executable("crashpad_snapshot_test_no_op") { testonly = true - sources = [ - "mac/mach_o_image_annotations_reader_test_no_op.cc", - ] + sources = [ "mac/mach_o_image_annotations_reader_test_no_op.cc" ] } } if (crashpad_is_win) { crashpad_executable("crashpad_snapshot_test_annotations") { testonly = true - sources = [ - "win/crashpad_snapshot_test_annotations.cc", - ] + sources = [ "win/crashpad_snapshot_test_annotations.cc" ] deps = [ "../client", "../compat", @@ -516,9 +498,7 @@ if (crashpad_is_win) { crashpad_executable("crashpad_snapshot_test_crashing_child") { testonly = true - sources = [ - "win/crashpad_snapshot_test_crashing_child.cc", - ] + sources = [ "win/crashpad_snapshot_test_crashing_child.cc" ] deps = [ "../client", "../compat", @@ -529,9 +509,7 @@ if (crashpad_is_win) { crashpad_executable("crashpad_snapshot_test_dump_without_crashing") { testonly = true - sources = [ - "win/crashpad_snapshot_test_dump_without_crashing.cc", - ] + sources = [ "win/crashpad_snapshot_test_dump_without_crashing.cc" ] deps = [ "../client", "../compat", @@ -542,9 +520,7 @@ if (crashpad_is_win) { crashpad_executable("crashpad_snapshot_test_extra_memory_ranges") { testonly = true - sources = [ - "win/crashpad_snapshot_test_extra_memory_ranges.cc", - ] + sources = [ "win/crashpad_snapshot_test_extra_memory_ranges.cc" ] deps = [ "../client", "../compat", @@ -554,9 +530,7 @@ if (crashpad_is_win) { crashpad_executable("crashpad_snapshot_test_image_reader") { testonly = true - sources = [ - "win/crashpad_snapshot_test_image_reader.cc", - ] + sources = [ "win/crashpad_snapshot_test_image_reader.cc" ] deps = [ "../client", "../compat", @@ -575,9 +549,7 @@ if (crashpad_is_win) { crashpad_loadable_module("crashpad_snapshot_test_image_reader_module") { testonly = true - sources = [ - "win/crashpad_snapshot_test_image_reader_module.cc", - ] + sources = [ "win/crashpad_snapshot_test_image_reader_module.cc" ] deps = [ "../client", "../third_party/mini_chromium:base", diff --git a/test/BUILD.gn b/test/BUILD.gn index f9c81324..e71ae246 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -130,9 +130,7 @@ static_library("test") { "../build:crashpad_is_in_fuchsia", ] - data = [ - "test_paths_test_data_root.txt", - ] + data = [ "test_paths_test_data_root.txt" ] deps = [ "../compat", @@ -161,9 +159,7 @@ static_library("test") { } if (crashpad_is_fuchsia) { - public_deps = [ - "../third_party/fuchsia", - ] + public_deps = [ "../third_party/fuchsia" ] if (crashpad_is_in_fuchsia) { deps += [ "//zircon/public/lib/fdio" ] } @@ -217,9 +213,7 @@ source_set("test_test") { "../util", ] - data_deps = [ - ":crashpad_test_test_multiprocess_exec_test_child", - ] + data_deps = [ ":crashpad_test_test_multiprocess_exec_test_child" ] if (crashpad_is_ios) { deps -= [ @@ -233,13 +227,9 @@ source_set("test_test") { if (!crashpad_is_ios) { crashpad_executable("crashpad_test_test_multiprocess_exec_test_child") { - sources = [ - "multiprocess_exec_test_child.cc", - ] + sources = [ "multiprocess_exec_test_child.cc" ] - deps = [ - "../third_party/mini_chromium:base", - ] + deps = [ "../third_party/mini_chromium:base" ] } } @@ -251,18 +241,14 @@ if (crashpad_is_ios) { "gtest_runner_ios.mm", ] configs += [ "..:crashpad_config" ] - deps = [ - "../third_party/gtest:gtest", - ] + deps = [ "../third_party/gtest:gtest" ] libs = [ "UIKit.framework" ] } } static_library("gmock_main") { testonly = true - sources = [ - "gtest_main.cc", - ] + sources = [ "gtest_main.cc" ] configs += [ "../build:crashpad_is_in_chromium" ] defines = [ "CRASHPAD_TEST_LAUNCHER_GMOCK" ] deps = [ @@ -279,9 +265,7 @@ static_library("gmock_main") { static_library("gtest_main") { testonly = true - sources = [ - "gtest_main.cc", - ] + sources = [ "gtest_main.cc" ] configs += [ "../build:crashpad_is_in_chromium" ] defines = [ "CRASHPAD_TEST_LAUNCHER_GTEST" ] deps = [ diff --git a/third_party/apple_cf/BUILD.gn b/third_party/apple_cf/BUILD.gn index 43c62eb2..9e37354d 100644 --- a/third_party/apple_cf/BUILD.gn +++ b/third_party/apple_cf/BUILD.gn @@ -13,7 +13,5 @@ # limitations under the License. source_set("apple_cf") { - sources = [ - "CFStreamAbstract.h", - ] + sources = [ "CFStreamAbstract.h" ] } diff --git a/third_party/cpp-httplib/BUILD.gn b/third_party/cpp-httplib/BUILD.gn index be2a6d74..2cbb72f5 100644 --- a/third_party/cpp-httplib/BUILD.gn +++ b/third_party/cpp-httplib/BUILD.gn @@ -15,7 +15,5 @@ source_set("cpp-httplib") { testonly = true include_dirs = [ "cpp-httplib" ] - sources = [ - "cpp-httplib/httplib.h", - ] + sources = [ "cpp-httplib/httplib.h" ] } diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 88866c62..4111c582 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -200,19 +200,13 @@ if (crashpad_is_in_fuchsia) { cpp_source, ] - deps = [ - ":fidlc_${fidl_source.library_name}", - ] + deps = [ ":fidlc_${fidl_source.library_name}" ] } source_set("${fidl_source.library_name}_tables") { - sources = [ - coding_tables, - ] + sources = [ coding_tables ] - deps = [ - ":fidlc_${fidl_source.library_name}", - ] + deps = [ ":fidlc_${fidl_source.library_name}" ] public_configs = [ ":fidl_config" ] } diff --git a/third_party/glibc/BUILD.gn b/third_party/glibc/BUILD.gn index e12febfe..3f2b08bc 100644 --- a/third_party/glibc/BUILD.gn +++ b/third_party/glibc/BUILD.gn @@ -13,7 +13,5 @@ # limitations under the License. source_set("glibc") { - sources = [ - "elf/elf.h", - ] + sources = [ "elf/elf.h" ] } diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index c2058e23..ae55259f 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -18,28 +18,20 @@ import("../../build/test.gni") if (crashpad_is_in_chromium) { group("gtest") { testonly = true - public_deps = [ - "//testing/gtest", - ] + public_deps = [ "//testing/gtest" ] } group("gmock") { testonly = true - public_deps = [ - "//testing/gmock", - ] + public_deps = [ "//testing/gmock" ] } } else if (crashpad_is_in_dart || crashpad_is_in_fuchsia) { group("gtest") { testonly = true - public_deps = [ - "//third_party/googletest:gtest", - ] + public_deps = [ "//third_party/googletest:gtest" ] } group("gmock") { testonly = true - public_deps = [ - "//third_party/googletest:gmock", - ] + public_deps = [ "//third_party/googletest:gmock" ] } } else if (crashpad_is_standalone) { config("gtest_private_config") { @@ -96,9 +88,7 @@ if (crashpad_is_in_chromium) { ] configs += [ ":gtest_private_config" ] if (crashpad_is_fuchsia) { - deps = [ - "../fuchsia", - ] + deps = [ "../fuchsia" ] } } @@ -107,12 +97,8 @@ if (crashpad_is_in_chromium) { visibility = [ ":*" ] testonly = true - sources = [ - "gtest/googletest/src/gtest_main.cc", - ] - deps = [ - ":gtest", - ] + sources = [ "gtest/googletest/src/gtest_main.cc" ] + deps = [ ":gtest" ] } test("gtest_all_test") { @@ -150,31 +136,19 @@ if (crashpad_is_in_chromium) { } test("gtest_environment_test") { - sources = [ - "gtest/googletest/test/gtest_environment_test.cc", - ] + sources = [ "gtest/googletest/test/gtest_environment_test.cc" ] configs += [ ":gtest_private_config" ] - deps = [ - ":gtest", - ] + deps = [ ":gtest" ] } test("gtest_listener_test") { - sources = [ - "gtest/googletest/test/googletest-listener-test.cc", - ] - deps = [ - ":gtest", - ] + sources = [ "gtest/googletest/test/googletest-listener-test.cc" ] + deps = [ ":gtest" ] } test("gtest_no_test") { - sources = [ - "gtest/googletest/test/gtest_no_test_unittest.cc", - ] - deps = [ - ":gtest", - ] + sources = [ "gtest/googletest/test/gtest_no_test_unittest.cc" ] + deps = [ ":gtest" ] } test("gtest_param_test") { @@ -187,9 +161,7 @@ if (crashpad_is_in_chromium) { "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", ] configs += [ ":gtest_private_config" ] - deps = [ - ":gtest", - ] + deps = [ ":gtest" ] if (crashpad_is_clang) { cflags_cc = [ @@ -201,28 +173,18 @@ if (crashpad_is_in_chromium) { } test("gtest_premature_exit_test") { - sources = [ - "gtest/googletest/test/gtest_premature_exit_test.cc", - ] - deps = [ - ":gtest", - ] + sources = [ "gtest/googletest/test/gtest_premature_exit_test.cc" ] + deps = [ ":gtest" ] } test("gtest_repeat_test") { - sources = [ - "gtest/googletest/test/gtest_repeat_test.cc", - ] + sources = [ "gtest/googletest/test/gtest_repeat_test.cc" ] configs += [ ":gtest_private_config" ] - deps = [ - ":gtest", - ] + deps = [ ":gtest" ] } test("gtest_sole_header_test") { - sources = [ - "gtest/googletest/test/gtest_sole_header_test.cc", - ] + sources = [ "gtest/googletest/test/gtest_sole_header_test.cc" ] deps = [ ":gtest", ":gtest_main", @@ -230,22 +192,14 @@ if (crashpad_is_in_chromium) { } test("gtest_stress_test") { - sources = [ - "gtest/googletest/test/gtest_stress_test.cc", - ] + sources = [ "gtest/googletest/test/gtest_stress_test.cc" ] configs += [ ":gtest_private_config" ] - deps = [ - ":gtest", - ] + deps = [ ":gtest" ] } test("gtest_unittest_api_test") { - sources = [ - "gtest/googletest/test/gtest-unittest-api_test.cc", - ] - deps = [ - ":gtest", - ] + sources = [ "gtest/googletest/test/gtest-unittest-api_test.cc" ] + deps = [ ":gtest" ] } group("gtest_all_tests") { @@ -319,18 +273,14 @@ if (crashpad_is_in_chromium) { "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", ] configs += [ ":gmock_private_config" ] - deps = [ - ":gtest", - ] + deps = [ ":gtest" ] } static_library("gmock_main") { # Tests outside of this file should use ../../test:gmock_main instead. visibility = [ ":*" ] testonly = true - sources = [ - "gtest/googlemock/src/gmock_main.cc", - ] + sources = [ "gtest/googlemock/src/gmock_main.cc" ] deps = [ ":gmock", ":gtest", @@ -389,9 +339,7 @@ if (crashpad_is_in_chromium) { } test("gmock_stress_test") { - sources = [ - "gtest/googlemock/test/gmock_stress_test.cc", - ] + sources = [ "gtest/googlemock/test/gmock_stress_test.cc" ] configs -= [ "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", ] diff --git a/third_party/lss/BUILD.gn b/third_party/lss/BUILD.gn index 1e0bd2bf..c0652cdf 100644 --- a/third_party/lss/BUILD.gn +++ b/third_party/lss/BUILD.gn @@ -25,7 +25,5 @@ config("lss_config") { source_set("lss") { public_configs = [ ":lss_config" ] - sources = [ - "lss.h", - ] + sources = [ "lss.h" ] } diff --git a/third_party/mini_chromium/BUILD.gn b/third_party/mini_chromium/BUILD.gn index 095267ff..50d15133 100644 --- a/third_party/mini_chromium/BUILD.gn +++ b/third_party/mini_chromium/BUILD.gn @@ -16,17 +16,11 @@ import("../../build/crashpad_buildconfig.gni") group("base") { if (crashpad_is_in_chromium) { - public_deps = [ - "//base", - ] + public_deps = [ "//base" ] } else if (crashpad_is_standalone || crashpad_is_in_fuchsia) { - public_deps = [ - "mini_chromium/base", - ] + public_deps = [ "mini_chromium/base" ] } else if (crashpad_is_in_dart) { - public_deps = [ - "//third_party/mini_chromium/mini_chromium/base" - ] + public_deps = [ "//third_party/mini_chromium/mini_chromium/base" ] } } @@ -34,8 +28,6 @@ group("base_test_support") { testonly = true if (crashpad_is_in_chromium) { - public_deps = [ - "//base/test:test_support", - ] + public_deps = [ "//base/test:test_support" ] } } diff --git a/third_party/xnu/BUILD.gn b/third_party/xnu/BUILD.gn index b6a94047..2079ecf0 100644 --- a/third_party/xnu/BUILD.gn +++ b/third_party/xnu/BUILD.gn @@ -13,7 +13,5 @@ # limitations under the License. source_set("xnu") { - sources = [ - "EXTERNAL_HEADERS/mach-o/loader.h", - ] + sources = [ "EXTERNAL_HEADERS/mach-o/loader.h" ] } diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn index 3267b981..1723c11d 100644 --- a/third_party/zlib/BUILD.gn +++ b/third_party/zlib/BUILD.gn @@ -36,9 +36,7 @@ config("zlib_config") { if (zlib_source == "external") { group("zlib") { public_configs = [ ":zlib_config" ] - public_deps = [ - "//third_party/zlib", - ] + public_deps = [ "//third_party/zlib" ] } } else if (zlib_source == "system") { source_set("zlib") { diff --git a/tools/BUILD.gn b/tools/BUILD.gn index 99332389..acd83b34 100644 --- a/tools/BUILD.gn +++ b/tools/BUILD.gn @@ -22,15 +22,11 @@ source_set("tool_support") { public_configs = [ "..:crashpad_config" ] - deps = [ - "../third_party/mini_chromium:base", - ] + deps = [ "../third_party/mini_chromium:base" ] } crashpad_executable("crashpad_database_util") { - sources = [ - "crashpad_database_util.cc", - ] + sources = [ "crashpad_database_util.cc" ] deps = [ ":tool_support", @@ -43,9 +39,7 @@ crashpad_executable("crashpad_database_util") { } crashpad_executable("crashpad_http_upload") { - sources = [ - "crashpad_http_upload.cc", - ] + sources = [ "crashpad_http_upload.cc" ] deps = [ ":tool_support", @@ -57,9 +51,7 @@ crashpad_executable("crashpad_http_upload") { } crashpad_executable("base94_encoder") { - sources = [ - "base94_encoder.cc", - ] + sources = [ "base94_encoder.cc" ] deps = [ ":tool_support", "../build:default_exe_manifest_win", @@ -71,9 +63,7 @@ crashpad_executable("base94_encoder") { if (!crashpad_is_fuchsia) { crashpad_executable("generate_dump") { - sources = [ - "generate_dump.cc", - ] + sources = [ "generate_dump.cc" ] deps = [ ":tool_support", @@ -89,9 +79,7 @@ if (!crashpad_is_fuchsia) { # This would be better as a config so that it could be shared with # exception_port_tool, but configs can’t alter “inputs”. # https://crbug.com/781858. - inputs = [ - "mac/sectaskaccess_info.plist", - ] + inputs = [ "mac/sectaskaccess_info.plist" ] ldflags = [ "-sectcreate", "__TEXT", @@ -108,9 +96,7 @@ if (!crashpad_is_fuchsia) { if (crashpad_is_mac || crashpad_is_fuchsia) { crashpad_executable("run_with_crashpad") { - sources = [ - "run_with_crashpad.cc", - ] + sources = [ "run_with_crashpad.cc" ] deps = [ ":tool_support", @@ -124,9 +110,7 @@ if (crashpad_is_mac || crashpad_is_fuchsia) { if (crashpad_is_mac) { crashpad_executable("catch_exception_tool") { - sources = [ - "mac/catch_exception_tool.cc", - ] + sources = [ "mac/catch_exception_tool.cc" ] deps = [ ":tool_support", @@ -137,15 +121,11 @@ if (crashpad_is_mac) { } crashpad_executable("exception_port_tool") { - sources = [ - "mac/exception_port_tool.cc", - ] + sources = [ "mac/exception_port_tool.cc" ] # This would be better as a config so that it could be shared with # generate_dump, but configs can’t alter “inputs”. https://crbug.com/781858. - inputs = [ - "mac/sectaskaccess_info.plist", - ] + inputs = [ "mac/sectaskaccess_info.plist" ] ldflags = [ "-sectcreate", "__TEXT", @@ -162,9 +142,7 @@ if (crashpad_is_mac) { } crashpad_executable("on_demand_service_tool") { - sources = [ - "mac/on_demand_service_tool.mm", - ] + sources = [ "mac/on_demand_service_tool.mm" ] libs = [ "CoreFoundation.framework", diff --git a/util/BUILD.gn b/util/BUILD.gn index 11d48445..f886d640 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -466,9 +466,7 @@ static_library("util") { include_dirs = [ "$root_gen_dir/third_party/crashpad/crashpad" ] } - public_deps = [ - "../compat", - ] + public_deps = [ "../compat" ] deps += [ "../third_party/mini_chromium:base", @@ -519,9 +517,7 @@ static_library("util") { if (!crashpad_is_android) { crashpad_executable("http_transport_test_server") { testonly = true - sources = [ - "net/http_transport_test_server.cc", - ] + sources = [ "net/http_transport_test_server.cc" ] deps = [ ":util", @@ -693,9 +689,7 @@ source_set("util_test") { } } - data = [ - "net/testdata/", - ] + data = [ "net/testdata/" ] deps = [ ":util", @@ -713,9 +707,7 @@ source_set("util_test") { } if (!crashpad_is_android) { - data_deps = [ - ":http_transport_test_server", - ] + data_deps = [ ":http_transport_test_server" ] if (crashpad_use_boringssl_for_http_transport_socket) { defines = [ "CRASHPAD_USE_BORINGSSL" ] @@ -742,25 +734,17 @@ source_set("util_test") { if (crashpad_is_win) { crashpad_executable("crashpad_util_test_process_info_test_child") { testonly = true - sources = [ - "win/process_info_test_child.cc", - ] + sources = [ "win/process_info_test_child.cc" ] } crashpad_executable("crashpad_util_test_safe_terminate_process_test_child") { testonly = true - sources = [ - "win/safe_terminate_process_test_child.cc", - ] + sources = [ "win/safe_terminate_process_test_child.cc" ] } crashpad_loadable_module("crashpad_util_test_loader_lock_test") { testonly = true - sources = [ - "win/loader_lock_test_dll.cc", - ] - deps = [ - ":util", - ] + sources = [ "win/loader_lock_test_dll.cc" ] + deps = [ ":util" ] } } From 6c0f5ccaa872501fedda8ed6f702515e61f27ad0 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 24 Jan 2020 10:36:14 -0800 Subject: [PATCH 315/401] Add NewReport::Reader to read back new reports Change-Id: If53a63aac2b213b02619bb5277e5618c0e7842b3 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2019566 Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crash_report_database.cc | 9 +++++++++ client/crash_report_database.h | 7 ++++++- client/crash_report_database_test.cc | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/client/crash_report_database.cc b/client/crash_report_database.cc index 8fad1721..eda0ef42 100644 --- a/client/crash_report_database.cc +++ b/client/crash_report_database.cc @@ -65,6 +65,15 @@ bool CrashReportDatabase::NewReport::Initialize( return true; } +FileReaderInterface* CrashReportDatabase::NewReport::Reader() { + auto reader = std::make_unique<FileReader>(); + if (!reader->Open(file_remover_.get())) { + return nullptr; + } + reader_ = std::move(reader); + return reader_.get(); +} + CrashReportDatabase::UploadReport::UploadReport() : Report(), reader_(std::make_unique<FileReader>()), diff --git a/client/crash_report_database.h b/client/crash_report_database.h index f3cc31cc..cc4b8dfa 100644 --- a/client/crash_report_database.h +++ b/client/crash_report_database.h @@ -113,9 +113,13 @@ class CrashReportDatabase { NewReport(); ~NewReport(); - //! An open FileWriter with which to write the report. + //! \brief An open FileWriter with which to write the report. FileWriter* Writer() const { return writer_.get(); } + //! \brief Returns a FileReaderInterface to the report, or `nullptr` with a + //! message logged. + FileReaderInterface* Reader(); + //! A unique identifier by which this report will always be known to the //! database. const UUID& ReportID() const { return uuid_; } @@ -142,6 +146,7 @@ class CrashReportDatabase { const base::FilePath::StringType& extension); std::unique_ptr<FileWriter> writer_; + std::unique_ptr<FileReader> reader_; ScopedRemoveFile file_remover_; std::vector<std::unique_ptr<FileWriter>> attachment_writers_; std::vector<ScopedRemoveFile> attachment_removers_; diff --git a/client/crash_report_database_test.cc b/client/crash_report_database_test.cc index ef217c19..20512a45 100644 --- a/client/crash_report_database_test.cc +++ b/client/crash_report_database_test.cc @@ -53,6 +53,12 @@ class CrashReportDatabaseTest : public testing::Test { static constexpr char kTest[] = "test"; ASSERT_TRUE(new_report->Writer()->Write(kTest, sizeof(kTest))); + char contents[sizeof(kTest)]; + FileReaderInterface* reader = new_report->Reader(); + ASSERT_TRUE(reader->ReadExactly(contents, sizeof(contents))); + EXPECT_EQ(memcmp(contents, kTest, sizeof(contents)), 0); + EXPECT_EQ(reader->ReadExactly(contents, 1), 0); + UUID uuid; EXPECT_EQ(db_->FinishedWritingCrashReport(std::move(new_report), &uuid), CrashReportDatabase::kNoError); From 23a2da5e955809c52c694eb0d7031084c8bdff81 Mon Sep 17 00:00:00 2001 From: "P.Y. Laligand" <pylaligand@google.com> Date: Tue, 28 Jan 2020 15:07:43 -0800 Subject: [PATCH 316/401] [fuchsia] Only add fdio config if it's not already present. Change-Id: Ie5eef8fb76b7a9558791aae8572ec2c91d2e6b84 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2026287 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Francois Rousseau <frousseau@google.com> --- build/crashpad_buildconfig.gni | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/crashpad_buildconfig.gni b/build/crashpad_buildconfig.gni index e1ef71f2..7540fb28 100644 --- a/build/crashpad_buildconfig.gni +++ b/build/crashpad_buildconfig.gni @@ -85,7 +85,10 @@ template("crashpad_executable") { } if (crashpad_is_in_fuchsia) { - configs += [ "//build/config/fuchsia:fdio_config" ] + fdio_config = [ "//build/config/fuchsia:fdio_config" ] + if (configs + fdio_config - fdio_config == configs) { + configs += fdio_config + } } } } From 77baffaf931b3e1c21cdc0e0f32aadd9856ea4eb Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Tue, 28 Jan 2020 15:34:34 -0500 Subject: [PATCH 317/401] Add iOS gn configs. Allows more native iOS development with Xcode by auto generating all the various configs during runhooks. Change-Id: I840001caabc7ef656c3145b847cee5596335aa23 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2024186 Reviewed-by: Rohit Rao <rohitrao@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- DEPS | 15 +- build/ios/convert_gn_xcodeproj.py | 273 +++++++++++++++++++++++ build/ios/setup-ios-gn.config | 39 ++++ build/ios/setup-ios-gn.py | 352 ++++++++++++++++++++++++++++++ 4 files changed, 678 insertions(+), 1 deletion(-) create mode 100644 build/ios/convert_gn_xcodeproj.py create mode 100644 build/ios/setup-ios-gn.config create mode 100644 build/ios/setup-ios-gn.py diff --git a/DEPS b/DEPS index a20b19c0..2e93b810 100644 --- a/DEPS +++ b/DEPS @@ -15,7 +15,11 @@ vars = { 'chromium_git': 'https://chromium.googlesource.com', 'pull_linux_clang': False, - 'pull_win_toolchain': False + 'pull_win_toolchain': False, + # Controls whether crashpad/build/ios/setup-ios-gn.py is run as part of + # gclient hooks. It is enabled by default for developer's convenience. It can + # be disabled with custom_vars (done automatically on the bots). + 'run_setup_ios_gn': True, } deps = { @@ -217,6 +221,15 @@ hooks = [ 'crashpad/build/install_linux_sysroot.py', ], }, + { + 'name': 'setup_gn_ios', + 'pattern': '.', + 'condition': 'run_setup_ios_gn and checkout_ios', + 'action': [ + 'python', + 'crashpad/build/ios/setup-ios-gn.py' + ], + }, ] recursedeps = [ diff --git a/build/ios/convert_gn_xcodeproj.py b/build/ios/convert_gn_xcodeproj.py new file mode 100644 index 00000000..b41d04ec --- /dev/null +++ b/build/ios/convert_gn_xcodeproj.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python + +# 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. + +"""Convert GN Xcode projects to platform and configuration independent targets. + +GN generates Xcode projects that build one configuration only. However, typical +iOS development involves using the Xcode IDE to toggle the platform and +configuration. This script replaces the 'gn' configuration with 'Debug', +'Release' and 'Profile', and changes the ninja invocation to honor these +configurations. +""" + +import argparse +import collections +import copy +import filecmp +import json +import hashlib +import os +import plistlib +import random +import shutil +import subprocess +import sys +import tempfile + + +class XcodeProject(object): + + def __init__(self, objects, counter = 0): + self.objects = objects + self.counter = 0 + + 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).hexdigest()[:24].upper() + + # Make sure ID is unique. It's possible there could be an id conflict + # since this is run after GN runs. + if new_id not in self.objects: + self.objects[new_id] = obj + return new_id + + +def CopyFileIfChanged(source_path, target_path): + """Copy |source_path| to |target_path| is different.""" + target_dir = os.path.dirname(target_path) + if not os.path.isdir(target_dir): + os.makedirs(target_dir) + if not os.path.exists(target_path) or \ + not filecmp.cmp(source_path, target_path): + shutil.copyfile(source_path, target_path) + + +def LoadXcodeProjectAsJSON(path): + """Return Xcode project at |path| as a JSON string.""" + return subprocess.check_output([ + 'plutil', '-convert', 'json', '-o', '-', path]) + + +def WriteXcodeProject(output_path, json_string): + """Save Xcode project to |output_path| as XML.""" + with tempfile.NamedTemporaryFile() as temp_file: + temp_file.write(json_string) + temp_file.flush() + subprocess.check_call(['plutil', '-convert', 'xml1', temp_file.name]) + CopyFileIfChanged(temp_file.name, output_path) + + +def UpdateProductsProject(file_input, file_output, configurations, root_dir): + """Update Xcode project to support multiple configurations. + + Args: + file_input: path to the input Xcode project + file_output: path to the output file + configurations: list of string corresponding to the configurations that + need to be supported by the tweaked Xcode projects, must contains at + least one value. + """ + json_data = json.loads(LoadXcodeProjectAsJSON(file_input)) + project = XcodeProject(json_data['objects']) + + objects_to_remove = [] + for value in project.objects.values(): + isa = value['isa'] + + # Teach build shell script to look for the configuration and platform. + if isa == 'PBXShellScriptBuildPhase': + value['shellScript'] = value['shellScript'].replace( + 'ninja -C .', + 'ninja -C "../${CONFIGURATION}${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)' + build_config_template['buildSettings']['CODE_SIGN_IDENTITY'] = '' + + 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)) + + for object_id in objects_to_remove: + del project.objects[object_id] + + AddMarkdownToProject(project, root_dir, json_data['rootObject']) + + objects = collections.OrderedDict(sorted(project.objects.iteritems())) + WriteXcodeProject(file_output, json.dumps(json_data)) + + +def AddMarkdownToProject(project, root_dir, root_object): + list_files_cmd = ['git', '-C', root_dir, 'ls-files', '*.md'] + paths = subprocess.check_output(list_files_cmd).splitlines() + ios_internal_dir = os.path.join(root_dir, 'ios_internal') + if os.path.exists(ios_internal_dir): + list_files_cmd = ['git', '-C', ios_internal_dir, 'ls-files', '*.md'] + ios_paths = subprocess.check_output(list_files_cmd).splitlines() + paths.extend(["ios_internal/" + path for path in ios_paths]) + for path in paths: + new_markdown_entry = { + "fileEncoding": "4", + "isa": "PBXFileReference", + "lastKnownFileType": "net.daringfireball.markdown", + "name": os.path.basename(path), + "path": path, + "sourceTree": "<group>" + } + new_markdown_entry_id = project.AddObject('sources', new_markdown_entry) + folder = GetFolderForPath(project, root_object, os.path.dirname(path)) + folder['children'].append(new_markdown_entry_id) + + +def GetFolderForPath(project, rootObject, path): + objects = project.objects + # 'Sources' is always the first child of + # project->rootObject->mainGroup->children. + root = objects[objects[objects[rootObject]['mainGroup']]['children'][0]] + if not path: + return root + for folder in path.split('/'): + children = root['children'] + new_root = None + for child in children: + if objects[child]['isa'] == 'PBXGroup' and \ + objects[child]['name'] == folder: + new_root = objects[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_group = { + "children": [ + ], + "isa": "PBXGroup", + "name": folder, + "sourceTree": "<group>" + } + new_group_id = project.AddObject('sources', new_group) + children.append(new_group_id) + new_root = objects[new_group_id] + root = new_root + return root + + +def DisableNewBuildSystem(output_dir): + """Disables the new build system due to crbug.com/852522 """ + xcwspacesharedsettings = os.path.join(output_dir, 'all.xcworkspace', + 'xcshareddata', 'WorkspaceSettings.xcsettings') + if os.path.isfile(xcwspacesharedsettings): + json_data = json.loads(LoadXcodeProjectAsJSON(xcwspacesharedsettings)) + else: + json_data = {} + json_data['BuildSystemType'] = 'Original' + WriteXcodeProject(xcwspacesharedsettings, json.dumps(json_data)) + + +def ConvertGnXcodeProject(root_dir, input_dir, output_dir, configurations): + '''Tweak the Xcode project generated by gn to support multiple configurations. + + The Xcode projects generated by "gn gen --ide" only supports a single + platform and configuration (as the platform and configuration are set + per output directory). This method takes as input such projects and + add support for multiple configurations and platforms (to allow devs + to select them in Xcode). + + Args: + 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. + ''' + # Update products project. + products = os.path.join('products.xcodeproj', 'project.pbxproj') + product_input = os.path.join(input_dir, products) + product_output = os.path.join(output_dir, products) + UpdateProductsProject(product_input, product_output, configurations, root_dir) + + # Copy all workspace. + xcwspace = os.path.join('all.xcworkspace', 'contents.xcworkspacedata') + CopyFileIfChanged(os.path.join(input_dir, xcwspace), + os.path.join(output_dir, xcwspace)) + + # TODO(crbug.com/852522): Disable new BuildSystemType. + DisableNewBuildSystem(output_dir) + + # TODO(crbug.com/679110): gn has been modified to remove 'sources.xcodeproj' + # and keep 'all.xcworkspace' and 'products.xcodeproj'. The following code is + # here to support both old and new projects setup and will be removed once gn + # has rolled past it. + sources = os.path.join('sources.xcodeproj', 'project.pbxproj') + if os.path.isfile(os.path.join(input_dir, sources)): + CopyFileIfChanged(os.path.join(input_dir, sources), + os.path.join(output_dir, sources)) + +def Main(args): + parser = argparse.ArgumentParser( + description='Convert GN Xcode projects for iOS.') + parser.add_argument( + 'input', + help='directory containing [product|all] Xcode projects.') + parser.add_argument( + 'output', + help='directory where to generate the iOS configuration.') + parser.add_argument( + '--add-config', dest='configurations', default=[], action='append', + help='configuration to add to the Xcode project') + parser.add_argument( + '--root', type=os.path.abspath, required=True, + help='root directory of the project') + args = parser.parse_args(args) + + if not os.path.isdir(args.input): + sys.stderr.write('Input directory does not exists.\n') + return 1 + + required = set(['products.xcodeproj', 'all.xcworkspace']) + if not required.issubset(os.listdir(args.input)): + sys.stderr.write( + 'Input directory does not contain all necessary Xcode projects.\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) + +if __name__ == '__main__': + sys.exit(Main(sys.argv[1:])) diff --git a/build/ios/setup-ios-gn.config b/build/ios/setup-ios-gn.config new file mode 100644 index 00000000..30c31115 --- /dev/null +++ b/build/ios/setup-ios-gn.config @@ -0,0 +1,39 @@ +# 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. + +[goma] +# Controls whether goma is enabled or not. If you generally use goma but +# want to disable goma for a single build, consider using the environment +# variable GOMA_DISABLED. +enabled = False +install = "$GOMA_DIR" + +[xcode] +# Controls settings for the generated Xcode project. If jobs is non-zero +# it will be passed to the ninja invocation in Xcode project. +jobs = 0 + +[build] +# Controls the build output. The only supported values are "64-bit", "32-bit" +# and "fat" (for a fat binary supporting both "32-bit" and "64-bit" cpus). +arch = "64-bit" + +[gn_args] +# Values in that section will be copied verbatim in the generated args.gn file. +target_os = "ios" + +[filters] +# List of target files to pass to --filters argument of gn gen when generating +# the Xcode project. By default, list all targets from ios/ and ios_internal/ +# and the targets corresponding to the unit tests run on the bots. diff --git a/build/ios/setup-ios-gn.py b/build/ios/setup-ios-gn.py new file mode 100644 index 00000000..995e3c84 --- /dev/null +++ b/build/ios/setup-ios-gn.py @@ -0,0 +1,352 @@ +#!/usr/bin/env python + +# 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. + + +import argparse +import convert_gn_xcodeproj +import errno +import os +import re +import shutil +import subprocess +import sys +import tempfile +import ConfigParser + +try: + import cStringIO as StringIO +except ImportError: + import StringIO + + +SUPPORTED_TARGETS = ('iphoneos', 'iphonesimulator') +SUPPORTED_CONFIGS = ('Debug', 'Release', 'Profile', 'Official', 'Coverage') + + +class ConfigParserWithStringInterpolation(ConfigParser.SafeConfigParser): + + '''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 (k, v): self._UnquoteString(self._ExpandEnvVar(v)), + ConfigParser.SafeConfigParser.items(self, section)) + + def getstring(self, section, option): + return self._UnquoteString(self._ExpandEnvVar(self.get(section, option))) + + 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.itervalues() 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 = StringIO.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 = StringIO.StringIO() + self.WriteArgsGn(buf) + WriteToFileIfChanged( + os.path.join(out_path, 'args.gn'), + buf.getvalue(), + overwrite=True) + + buf = StringIO.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 = StringIO.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') + + 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') + 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('--root-target=gn_all') + if self._settings.getboolean('goma', 'enabled'): + ninja_jobs = self._settings.getint('xcode', 'jobs') or 200 + gn_command.append('--ninja-extra-args=-j%s' % ninja_jobs) + if self._settings.has_section('filters'): + target_filters = self._settings.values('filters') + if target_filters: + gn_command.append('--filters=%s' % ';'.join(target_filters)) + # TODO(justincohen): --check is currently failing in crashpad. + # 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) + + +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 + + +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) + + +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) + + +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) + + +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') + 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) + + if settings.getboolean('goma', 'enabled'): + if settings.getint('xcode', 'jobs') < 0: + sys.stderr.write('ERROR: invalid value for xcode.jobs: %s\n' % + settings.get('xcode', 'jobs')) + sys.exit(1) + goma_install = os.path.expanduser(settings.getstring('goma', 'install')) + if not os.path.isdir(goma_install): + sys.stderr.write('WARNING: goma.install directory not found: %s\n' % + settings.get('goma', 'install')) + sys.stderr.write('WARNING: disabling goma\n') + settings.set('goma', 'enabled', 'false') + + # Find gn binary in PATH. + 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, 'out') + 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) + + +if __name__ == '__main__': + sys.exit(Main(sys.argv[1:])) From f36f46d1ec95299218505ef0b3c6d9ba7baeef33 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Wed, 29 Jan 2020 21:31:33 -0500 Subject: [PATCH 318/401] Roll crashpad/third_party/mini_chromium/mini_chromium/ 0512d4269..f58366399 (1 commit) https://chromium.googlesource.com/chromium/mini_chromium/+log/0512d42698bf..f58366399b4e $ git log 0512d4269..f58366399 --date=short --no-merges --format='%ad %ae %s' 2020-01-29 justincohen Enable debug flags in debug mini chromium. Created with: roll-dep crashpad/third_party/mini_chromium/mini_chromium Change-Id: Ieb457f27b31c3717810f2be236b084127277de55 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2029649 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 2e93b810..5d0e0f77 100644 --- a/DEPS +++ b/DEPS @@ -37,7 +37,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '0512d42698bfb47f2016ac627177c22d22b983d4', + 'f58366399b4e50413773fbb2f9a1a5e7289462c1', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 915862984c1e727bc16594aafb9f586e9a587eb3 Mon Sep 17 00:00:00 2001 From: Tao Bai <michaelbai@chromium.org> Date: Tue, 28 Jan 2020 12:02:55 -0800 Subject: [PATCH 319/401] [log minidump] add option to log minidump in handler_main - Add option to log minidump in handler_main, also add option to disable to dump minidump and generate report. - Implement log minidump in CrashReportExceptionHandler. Bug: crashpad:308 Change-Id: I8d2f7e118912011a8416f1ec36c9ee9d561d06e6 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1995825 Commit-Queue: Tao Bai <michaelbai@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- handler/crashpad_handler.md | 12 +++ handler/handler_main.cc | 60 ++++++++++++- .../linux/crash_report_exception_handler.cc | 89 +++++++++++++++++-- .../linux/crash_report_exception_handler.h | 18 ++++ minidump/minidump_file_writer.cc | 19 +++- minidump/minidump_file_writer.h | 15 ++++ minidump/minidump_file_writer_test.cc | 63 +++++++++++++ tools/BUILD.gn | 1 - util/BUILD.gn | 10 ++- util/file/output_stream_file_writer.cc | 68 ++++++++++++++ util/file/output_stream_file_writer.h | 62 +++++++++++++ 11 files changed, 403 insertions(+), 14 deletions(-) create mode 100644 util/file/output_stream_file_writer.cc create mode 100644 util/file/output_stream_file_writer.h diff --git a/handler/crashpad_handler.md b/handler/crashpad_handler.md index f7e63a50..6d055ed1 100644 --- a/handler/crashpad_handler.md +++ b/handler/crashpad_handler.md @@ -233,6 +233,12 @@ establish the Crashpad client environment before running a program. for use with collection servers that don’t accept uploads compressed in this way. + * **--no-write-minidump-to-database** + + Do not write the minidump to database. Normally, the minidump is written to + database for upload. Use this option with **--write-minidump-to-log** to + only write the minidump to log. This option is only available to Android. + * **--pipe-name**=_PIPE_ Listen on the given pipe name for connections from clients. _PIPE_ must be of @@ -286,6 +292,12 @@ establish the Crashpad client environment before running a program. is still used for Crashpad settings. This option is only valid on Chromium OS. +* **--write-minidump-to-log** + + Write the minidump to log. By default the minidump is only written to + database. Use this option with **--no-write-minidump-to-database** to only + write the minidump to log. This option is only available to Android. + * **--help** Display help and exit. diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 1cf655ae..81c9a00a 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -143,6 +143,10 @@ 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) +" --no-write-minidump-to-database\n" +" don't write minidump to database\n" +#endif // OS_ANDROID #if defined(OS_WIN) " --pipe-name=PIPE communicate with the client over PIPE\n" #endif // OS_WIN @@ -173,6 +177,9 @@ void Usage(const base::FilePath& me) { " crash_reporter, thus skipping metrics consent\n" " checks\n" #endif // OS_CHROMEOS +#if defined(OS_ANDROID) +" --write-minidump-to-log write minidump to log\n" +#endif // OS_ANDROID " --help display this help and exit\n" " --version output version information and exit\n", me.value().c_str()); @@ -195,6 +202,10 @@ struct Options { VMAddress sanitization_information_address; int initial_client_fd; bool shared_client_connection; +#if defined(OS_ANDROID) + bool write_minidump_to_log; + bool write_minidump_to_database; +#endif // OS_ANDROID #elif defined(OS_WIN) std::string pipe_name; InitialClientData initial_client_data; @@ -551,6 +562,9 @@ int HandlerMain(int argc, kOptionNoPeriodicTasks, kOptionNoRateLimit, kOptionNoUploadGzip, +#if defined(OS_ANDROID) + kOptionNoWriteMinidumpToDatabase, +#endif // OS_ANDROID #if defined(OS_WIN) kOptionPipeName, #endif // OS_WIN @@ -568,6 +582,9 @@ int HandlerMain(int argc, kOptionMinidumpDirForTests, kOptionAlwaysAllowFeedback, #endif // OS_CHROMEOS +#if defined(OS_ANDROID) + kOptionWriteMinidumpToLog, +#endif // OS_ANDROID // Standard options. kOptionHelp = -2, @@ -609,6 +626,12 @@ 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) + {"no-write-minidump-to-database", + no_argument, + nullptr, + kOptionNoWriteMinidumpToDatabase}, +#endif // OS_ANDROID #if defined(OS_WIN) {"pipe-name", required_argument, nullptr, kOptionPipeName}, #endif // OS_WIN @@ -647,6 +670,9 @@ int HandlerMain(int argc, nullptr, kOptionAlwaysAllowFeedback}, #endif // OS_CHROMEOS +#if defined(OS_ANDROID) + {"write-minidump-to-log", no_argument, nullptr, kOptionWriteMinidumpToLog}, +#endif // OS_ANDROID {"help", no_argument, nullptr, kOptionHelp}, {"version", no_argument, nullptr, kOptionVersion}, {nullptr, 0, nullptr, 0}, @@ -663,6 +689,9 @@ int HandlerMain(int argc, options.periodic_tasks = true; options.rate_limit = true; options.upload_gzip = true; +#if defined(OS_ANDROID) + options.write_minidump_to_database = true; +#endif int opt; while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) { @@ -749,6 +778,12 @@ int HandlerMain(int argc, options.upload_gzip = false; break; } +#if defined(OS_ANDROID) + case kOptionNoWriteMinidumpToDatabase: { + options.write_minidump_to_database = false; + break; + } +#endif // OS_ANDROID #if defined(OS_WIN) case kOptionPipeName: { options.pipe_name = optarg; @@ -803,6 +838,12 @@ int HandlerMain(int argc, break; } #endif // OS_CHROMEOS +#if defined(OS_ANDROID) + case kOptionWriteMinidumpToLog: { + options.write_minidump_to_log = true; + break; + } +#endif // OS_ANDROID case kOptionHelp: { Usage(me); MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); @@ -863,6 +904,14 @@ int HandlerMain(int argc, me, "--shared-client-connection requires --initial-client-fd"); return ExitFailure(); } +#if defined(OS_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_MACOSX if (options.database.empty()) { @@ -966,8 +1015,17 @@ int HandlerMain(int argc, // TODO(scottmg): Process level file attachments, and for all platforms. nullptr, #endif - user_stream_sources); +#if defined(OS_ANDROID) + options.write_minidump_to_database, + options.write_minidump_to_log, +#endif // OS_ANDROID +#if defined(OS_LINUX) + true, + false, +#endif // OS_LINUX #endif // OS_CHROMEOS + user_stream_sources); + #if defined(OS_LINUX) || defined(OS_ANDROID) if (options.exception_information_address) { diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 9b4f2012..29f6d0db 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -23,23 +23,56 @@ #include "minidump/minidump_file_writer.h" #include "snapshot/linux/process_snapshot_linux.h" #include "snapshot/sanitized/process_snapshot_sanitized.h" +#include "util/file/file_reader.h" +#include "util/file/output_stream_file_writer.h" #include "util/linux/direct_ptrace_connection.h" #include "util/linux/ptrace_client.h" #include "util/misc/implicit_cast.h" #include "util/misc/metrics.h" #include "util/misc/uuid.h" +#include "util/stream/base94_output_stream.h" +#include "util/stream/log_output_stream.h" +#include "util/stream/zlib_output_stream.h" namespace crashpad { +namespace { + +bool WriteMinidumpLogFromFile(FileReaderInterface* file_reader) { + ZlibOutputStream stream(ZlibOutputStream::Mode::kCompress, + std::make_unique<Base94OutputStream>( + Base94OutputStream::Mode::kEncode, + std::make_unique<LogOutputStream>())); + FileOperationResult read_result; + do { + uint8_t buffer[4096]; + read_result = file_reader->Read(buffer, sizeof(buffer)); + if (read_result < 0) + return false; + + if (read_result > 0 && (!stream.Write(buffer, read_result))) + return false; + } while (read_result > 0); + return stream.Flush(); +} + +} // namespace + CrashReportExceptionHandler::CrashReportExceptionHandler( CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map<std::string, std::string>* process_annotations, + bool write_minidump_to_database, + bool write_minidump_to_log, const UserStreamDataSources* user_stream_data_sources) : database_(database), upload_thread_(upload_thread), process_annotations_(process_annotations), - user_stream_data_sources_(user_stream_data_sources) {} + write_minidump_to_database_(write_minidump_to_database), + write_minidump_to_log_(write_minidump_to_log), + user_stream_data_sources_(user_stream_data_sources) { + DCHECK(write_minidump_to_database_ | write_minidump_to_log_); +} CrashReportExceptionHandler::~CrashReportExceptionHandler() = default; @@ -116,6 +149,20 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( } process_snapshot->SetClientID(client_id); + return write_minidump_to_database_ + ? WriteMinidumpToDatabase(process_snapshot.get(), + sanitized_snapshot.get(), + write_minidump_to_log_, + local_report_id) + : WriteMinidumpToLog(process_snapshot.get(), + sanitized_snapshot.get()); +} + +bool CrashReportExceptionHandler::WriteMinidumpToDatabase( + ProcessSnapshotLinux* process_snapshot, + ProcessSnapshotSanitized* sanitized_snapshot, + bool write_minidump_to_log, + UUID* local_report_id) { std::unique_ptr<CrashReportDatabase::NewReport> new_report; CrashReportDatabase::OperationStatus database_status = database_->PrepareNewCrashReport(&new_report); @@ -129,9 +176,8 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( process_snapshot->SetReportID(new_report->ReportID()); ProcessSnapshot* snapshot = - sanitized_snapshot - ? implicit_cast<ProcessSnapshot*>(sanitized_snapshot.get()) - : implicit_cast<ProcessSnapshot*>(process_snapshot.get()); + sanitized_snapshot ? implicit_cast<ProcessSnapshot*>(sanitized_snapshot) + : implicit_cast<ProcessSnapshot*>(process_snapshot); MinidumpFileWriter minidump; minidump.InitializeFromSnapshot(snapshot); @@ -144,6 +190,16 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( return false; } + bool write_minidump_to_log_succeed = false; + if (write_minidump_to_log) { + if (auto* file_reader = new_report->Reader()) { + if (WriteMinidumpLogFromFile(file_reader)) + write_minidump_to_log_succeed = true; + else + LOG(ERROR) << "WriteMinidumpLogFromFile failed"; + } + } + UUID uuid; database_status = database_->FinishedWritingCrashReport(std::move(new_report), &uuid); @@ -163,7 +219,30 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( } Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSuccess); - return true; + + return write_minidump_to_log ? write_minidump_to_log_succeed : true; +} + +bool CrashReportExceptionHandler::WriteMinidumpToLog( + ProcessSnapshotLinux* process_snapshot, + ProcessSnapshotSanitized* sanitized_snapshot) { + ProcessSnapshot* snapshot = + sanitized_snapshot ? implicit_cast<ProcessSnapshot*>(sanitized_snapshot) + : implicit_cast<ProcessSnapshot*>(process_snapshot); + MinidumpFileWriter minidump; + minidump.InitializeFromSnapshot(snapshot); + AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump); + + OutputStreamFileWriter writer(std::make_unique<ZlibOutputStream>( + ZlibOutputStream::Mode::kCompress, + std::make_unique<Base94OutputStream>( + Base94OutputStream::Mode::kEncode, + std::make_unique<LogOutputStream>()))); + if (!minidump.WriteMinidump(&writer, false /* allow_seek */)) { + LOG(ERROR) << "WriteMinidump failed"; + return false; + } + return writer.Flush(); } } // namespace crashpad diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index 522a77de..83d07c0b 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -30,6 +30,9 @@ namespace crashpad { +class ProcessSnapshotLinux; +class ProcessSnapshotSanitized; + //! \brief An exception handler that writes crash reports for exceptions //! to a CrashReportDatabase. class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { @@ -50,6 +53,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] write_minidump_to_database Whether the minidump shall be + //! written to database. + //! \param[in] write_minidump_to_log Whether the minidump shall be written to + //! log. //! \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 +65,8 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { CrashReportDatabase* database, CrashReportUploadThread* upload_thread, const std::map<std::string, std::string>* process_annotations, + bool write_minidump_to_database, + bool write_minidump_to_log, const UserStreamDataSources* user_stream_data_sources); ~CrashReportExceptionHandler() override; @@ -87,9 +96,18 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { pid_t* requesting_thread_id, UUID* local_report_id = nullptr); + bool WriteMinidumpToDatabase(ProcessSnapshotLinux* process_snapshot, + ProcessSnapshotSanitized* sanitized_snapshot, + bool write_minidump_to_log, + UUID* local_report_id); + bool WriteMinidumpToLog(ProcessSnapshotLinux* process_snapshot, + ProcessSnapshotSanitized* sanitized_snapshot); + CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak const std::map<std::string, std::string>* process_annotations_; // weak + bool write_minidump_to_database_; + bool write_minidump_to_log_; const UserStreamDataSources* user_stream_data_sources_; // weak DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler); diff --git a/minidump/minidump_file_writer.cc b/minidump/minidump_file_writer.cc index f29a6fae..6727a0dc 100644 --- a/minidump/minidump_file_writer.cc +++ b/minidump/minidump_file_writer.cc @@ -211,17 +211,30 @@ bool MinidumpFileWriter::AddUserExtensionStream( } bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) { + return WriteMinidump(file_writer, true); +} + +bool MinidumpFileWriter::WriteMinidump(FileWriterInterface* file_writer, + bool allow_seek) { DCHECK_EQ(state(), kStateMutable); - FileOffset start_offset = file_writer->Seek(0, SEEK_CUR); - if (start_offset < 0) { - return false; + FileOffset start_offset = -1; + if (allow_seek) { + start_offset = file_writer->Seek(0, SEEK_CUR); + if (start_offset < 0) { + return false; + } + } else { + header_.Signature = MINIDUMP_SIGNATURE; } if (!MinidumpWritable::WriteEverything(file_writer)) { return false; } + if (!allow_seek) + return true; + FileOffset end_offset = file_writer->Seek(0, SEEK_CUR); if (end_offset < 0) { return false; diff --git a/minidump/minidump_file_writer.h b/minidump/minidump_file_writer.h index ce2f1d75..0a1b064f 100644 --- a/minidump/minidump_file_writer.h +++ b/minidump/minidump_file_writer.h @@ -134,6 +134,21 @@ class MinidumpFileWriter final : public internal::MinidumpWritable { //! mistaken for valid ones. bool WriteEverything(FileWriterInterface* file_writer) override; + //! \brief Writes this object to a minidump file. + //! + //! Same as \a WriteEverything, but give the option to disable the seek. It + //! is typically used to write to stream backed \a FileWriterInterface which + //! doesn't support seek. + //! + //! \param[in] file_writer The file writer to receive the minidump file’s + //! content. + //! + //! \param[in] allow_seek Whether seek is allowed. + //! + //! \return `true` on success. `false` on failure, with an appropriate message + //! logged. + bool WriteMinidump(FileWriterInterface* file_writer, bool allow_seek); + protected: // MinidumpWritable: bool Freeze() override; diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index 84832292..19eaae41 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -36,7 +36,9 @@ #include "snapshot/test/test_system_snapshot.h" #include "snapshot/test/test_thread_snapshot.h" #include "test/gtest_death.h" +#include "util/file/output_stream_file_writer.h" #include "util/file/string_file.h" +#include "util/stream/output_stream_interface.h" namespace crashpad { namespace test { @@ -88,6 +90,22 @@ class TestStream final : public internal::MinidumpStreamWriter { DISALLOW_COPY_AND_ASSIGN(TestStream); }; +class StringFileOutputStream : public OutputStreamInterface { + public: + StringFileOutputStream() = default; + ~StringFileOutputStream() override = default; + bool Write(const uint8_t* data, size_t size) override { + return string_file_.Write(data, size); + } + bool Flush() override { return true; } + const StringFile& string_file() const { return string_file_; } + + private: + StringFile string_file_; + + DISALLOW_COPY_AND_ASSIGN(StringFileOutputStream); +}; + TEST(MinidumpFileWriter, OneStream) { MinidumpFileWriter minidump_file; constexpr time_t kTimestamp = 0x155d2fb8; @@ -578,6 +596,51 @@ TEST(MinidumpFileWriter, SameStreamType) { EXPECT_EQ(memcmp(stream_data, expected_stream.c_str(), kStream0Size), 0); } +TEST(MinidumpFileWriter, WriteMinidumpDisallowSeek) { + MinidumpFileWriter minidump_file; + constexpr time_t kTimestamp = 0x155d2fb8; + minidump_file.SetTimestamp(kTimestamp); + + constexpr size_t kStreamSize = 5; + constexpr MinidumpStreamType kStreamType = + static_cast<MinidumpStreamType>(0x4d); + constexpr uint8_t kStreamValue = 0x5a; + auto stream = + std::make_unique<TestStream>(kStreamType, kStreamSize, kStreamValue); + ASSERT_TRUE(minidump_file.AddStream(std::move(stream))); + + std::unique_ptr<StringFileOutputStream> string_file_output_stream = + std::make_unique<StringFileOutputStream>(); + const StringFile& string_file = string_file_output_stream->string_file(); + OutputStreamFileWriter output_stream(std::move(string_file_output_stream)); + ASSERT_TRUE(minidump_file.WriteMinidump(&output_stream, false)); + ASSERT_TRUE(output_stream.Flush()); + + constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); + constexpr size_t kStreamOffset = + kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); + constexpr size_t kFileSize = kStreamOffset + kStreamSize; + + ASSERT_EQ(string_file.string().size(), kFileSize); + + const MINIDUMP_DIRECTORY* directory; + const MINIDUMP_HEADER* header = + MinidumpHeaderAtStart(string_file.string(), &directory); + ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, kTimestamp)); + ASSERT_TRUE(directory); + + EXPECT_EQ(directory[0].StreamType, kStreamType); + EXPECT_EQ(directory[0].Location.DataSize, kStreamSize); + EXPECT_EQ(directory[0].Location.Rva, kStreamOffset); + + const uint8_t* stream_data = MinidumpWritableAtLocationDescriptor<uint8_t>( + string_file.string(), directory[0].Location); + ASSERT_TRUE(stream_data); + + std::string expected_stream(kStreamSize, kStreamValue); + EXPECT_EQ(memcmp(stream_data, expected_stream.c_str(), kStreamSize), 0); +} + } // namespace } // namespace test } // namespace crashpad diff --git a/tools/BUILD.gn b/tools/BUILD.gn index acd83b34..41f0fb69 100644 --- a/tools/BUILD.gn +++ b/tools/BUILD.gn @@ -56,7 +56,6 @@ crashpad_executable("base94_encoder") { ":tool_support", "../build:default_exe_manifest_win", "../third_party/mini_chromium:base", - "../third_party/zlib", "../util", ] } diff --git a/util/BUILD.gn b/util/BUILD.gn index f886d640..f057fd96 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -91,6 +91,8 @@ static_library("util") { "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", @@ -466,13 +468,13 @@ static_library("util") { include_dirs = [ "$root_gen_dir/third_party/crashpad/crashpad" ] } - public_deps = [ "../compat" ] - - deps += [ - "../third_party/mini_chromium:base", + public_deps = [ + "../compat", "../third_party/zlib", ] + deps += [ "../third_party/mini_chromium:base" ] + if (crashpad_is_mac) { libs = [ "bsm", diff --git a/util/file/output_stream_file_writer.cc b/util/file/output_stream_file_writer.cc new file mode 100644 index 00000000..1172019e --- /dev/null +++ b/util/file/output_stream_file_writer.cc @@ -0,0 +1,68 @@ +// 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 "util/file/output_stream_file_writer.h" + +#include "base/logging.h" +#include "util/stream/output_stream_interface.h" + +namespace crashpad { + +OutputStreamFileWriter::OutputStreamFileWriter( + std::unique_ptr<OutputStreamInterface> output_stream) + : output_stream_(std::move(output_stream)), + flush_needed_(false), + flushed_(false) {} + +OutputStreamFileWriter::~OutputStreamFileWriter() { + DCHECK(!flush_needed_); +} + +bool OutputStreamFileWriter::Write(const void* data, size_t size) { + DCHECK(!flushed_); + flush_needed_ = + output_stream_->Write(static_cast<const uint8_t*>(data), size); + return flush_needed_; +} + +bool OutputStreamFileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) { + DCHECK(!flushed_); + flush_needed_ = true; + if (iovecs->empty()) { + LOG(ERROR) << "no iovecs"; + flush_needed_ = false; + return false; + } + for (const WritableIoVec& iov : *iovecs) { + if (!output_stream_->Write(static_cast<const uint8_t*>(iov.iov_base), + iov.iov_len)) { + flush_needed_ = false; + return false; + } + } + return true; +} + +FileOffset OutputStreamFileWriter::Seek(FileOffset offset, int whence) { + NOTREACHED(); + return -1; +} + +bool OutputStreamFileWriter::Flush() { + flush_needed_ = false; + flushed_ = true; + return output_stream_->Flush(); +} + +} // namespace crashpad diff --git a/util/file/output_stream_file_writer.h b/util/file/output_stream_file_writer.h new file mode 100644 index 00000000..6bf1c2c1 --- /dev/null +++ b/util/file/output_stream_file_writer.h @@ -0,0 +1,62 @@ +// 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_UTIL_FILE_OUTPUT_STREAM_FILE_WRITER_H_ +#define CRASHPAD_UTIL_FILE_OUTPUT_STREAM_FILE_WRITER_H_ + +#include <memory> + +#include "base/macros.h" +#include "util/file/file_writer.h" + +namespace crashpad { + +class OutputStreamInterface; + +//! \brief A file writer backed by a OutputSteamInterface. +//! \note The \a Seek related methods don't work and shouldn't be invoked. +class OutputStreamFileWriter : public FileWriterInterface { + public: + //! \param[in] output_stream The output stream that this object writes to. + explicit OutputStreamFileWriter( + std::unique_ptr<OutputStreamInterface> output_stream); + ~OutputStreamFileWriter() override; + + // FileWriterInterface: + bool Write(const void* data, size_t size) override; + bool WriteIoVec(std::vector<WritableIoVec>* iovecs) override; + + // FileSeekerInterface: + + //! \copydoc FileWriterInterface::Seek() + //! + //! \note This method doesn't work and shouldn't be invoked. + FileOffset Seek(FileOffset offset, int whence) override; + + //! \brief Flush data to output_stream. + //! + //! Either \a Write() or \a WriteIoVec() can't be called afterwards. + bool Flush(); + + private: + std::unique_ptr<OutputStreamInterface> output_stream_; + bool flush_needed_; + bool flushed_; + + DISALLOW_COPY_AND_ASSIGN(OutputStreamFileWriter); +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_FILE_OUTPUT_STREAM_FILE_WRITER_H_ From 75ea787a80c77867e09e97ae60d3476604334f5d Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Thu, 30 Jan 2020 22:11:26 -0500 Subject: [PATCH 320/401] Adds plumbing for xcuitests with a placeholder test. Also adds basic integration for EDO. Change-Id: If3d193a4967a566b55d6d446585e2988dacad6e6 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2028183 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Rohit Rao <rohitrao@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- .gitignore | 1 + BUILD.gn | 13 ++- DEPS | 5 + test/ios/BUILD.gn | 50 +++++++++ test/ios/crash_type_xctest.mm | 39 +++++++ test/ios/host/BUILD.gn | 62 +++++++++++ test/ios/host/Info.plist | 112 +++++++++++++++++++ test/ios/host/application_delegate.h | 23 ++++ test/ios/host/application_delegate.mm | 53 +++++++++ test/ios/host/crash_view_controller.h | 23 ++++ test/ios/host/crash_view_controller.mm | 33 ++++++ test/ios/host/edo_placeholder.h | 24 +++++ test/ios/host/main.mm | 30 ++++++ third_party/edo/BUILD.gn | 142 +++++++++++++++++++++++++ third_party/edo/README.crashpad | 10 ++ third_party/gtest/BUILD.gn | 106 +++++++++++++----- 16 files changed, 697 insertions(+), 29 deletions(-) create mode 100644 test/ios/BUILD.gn create mode 100644 test/ios/crash_type_xctest.mm create mode 100644 test/ios/host/BUILD.gn create mode 100644 test/ios/host/Info.plist create mode 100644 test/ios/host/application_delegate.h create mode 100644 test/ios/host/application_delegate.mm create mode 100644 test/ios/host/crash_view_controller.h create mode 100644 test/ios/host/crash_view_controller.mm create mode 100644 test/ios/host/edo_placeholder.h create mode 100644 test/ios/host/main.mm create mode 100644 third_party/edo/BUILD.gn create mode 100644 third_party/edo/README.crashpad diff --git a/.gitignore b/.gitignore index eee931eb..fe8a94c7 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ .gdbinit /Makefile /out +/third_party/edo/edo /third_party/fuchsia/.cipd /third_party/fuchsia/clang /third_party/fuchsia/qemu diff --git a/BUILD.gn b/BUILD.gn index f47c6aa2..0ea3187b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -121,7 +121,9 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { } package("crashpad_database_util") { - deps = [ "tools:crashpad_database_util" ] + deps = [ + "tools:crashpad_database_util", + ] binaries = [ { @@ -189,3 +191,12 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { } } } + +if (crashpad_is_ios) { + group("ios_xcuitests") { + testonly = true + deps = [ + "test/ios:all_tests", + ] + } +} diff --git a/DEPS b/DEPS index 5d0e0f77..6e4ac6d8 100644 --- a/DEPS +++ b/DEPS @@ -26,6 +26,11 @@ deps = { 'buildtools': Var('chromium_git') + '/chromium/src/buildtools.git@' + '3e50219fc4503f461b2176a9976891b28d80f9ab', + 'crashpad/third_party/edo/edo': { + 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + + '243fc89ae95b24717d41f3786f6a9abeeef87c92', + 'condition': 'checkout_ios', + }, 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + 'eb78ee170ac9eb21487f4d127720c060351fa8a2', diff --git a/test/ios/BUILD.gn b/test/ios/BUILD.gn new file mode 100644 index 00000000..722c4cae --- /dev/null +++ b/test/ios/BUILD.gn @@ -0,0 +1,50 @@ +# 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. + +import("../../build/crashpad_buildconfig.gni") + +if (crashpad_is_in_chromium) { + import("//build/config/ios/rules.gni") +} else if (crashpad_is_standalone) { + import("//third_party/mini_chromium/mini_chromium/build/ios/rules.gni") +} + +group("all_tests") { + testonly = true + deps = [ + ":ios_crash_xcuitests_module", + "host:ios_crash_xcuitests", + ] +} + +source_set("xcuitests") { + testonly = true + sources = [ + "crash_type_xctest.mm", + ] + configs += [ "../..:crashpad_config" ] + deps = [ + "../../build:ios_enable_arc", + "../../build:ios_xctest", + "../../test/ios/host:app_shared_sources", + "../../third_party/edo", + ] +} + +ios_xcuitest_test("ios_crash_xcuitests_module") { + xcode_test_application_name = "ios_crash_xcuitests" + deps = [ + ":xcuitests", + ] +} diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm new file mode 100644 index 00000000..ed72f613 --- /dev/null +++ b/test/ios/crash_type_xctest.mm @@ -0,0 +1,39 @@ +// 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. + +#import <XCTest/XCTest.h> + +#import "Service/Sources/EDOClientService.h" +#import "test/ios/host/edo_placeholder.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface CPTestTestCase : XCTestCase +@end + +@implementation CPTestTestCase + +- (void)setUp { + [[[XCUIApplication alloc] init] launch]; +} + +- (void)testEDO { + EDOPlaceholder* rootObject = [EDOClientService rootObjectWithPort:12345]; + NSString* result = [rootObject testEDO]; + XCTAssertEqualObjects(result, @"crashpad"); +} + +@end diff --git a/test/ios/host/BUILD.gn b/test/ios/host/BUILD.gn new file mode 100644 index 00000000..39c8d999 --- /dev/null +++ b/test/ios/host/BUILD.gn @@ -0,0 +1,62 @@ +# 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. + +import("../../../build/crashpad_buildconfig.gni") + +if (crashpad_is_in_chromium) { + import("//build/config/ios/rules.gni") +} else if (crashpad_is_standalone) { + import("//third_party/mini_chromium/mini_chromium/build/ios/rules.gni") +} + +source_set("app_shared_sources") { + testonly = true + sources = [ + "edo_placeholder.h", + ] + configs += [ "../../..:crashpad_config" ] + deps = [ + "../../../build:ios_enable_arc", + ] + libs = [ "UIKit.framework" ] +} + +static_library("app_host_sources") { + testonly = true + sources = [ + "application_delegate.h", + "application_delegate.mm", + "crash_view_controller.h", + "crash_view_controller.mm", + "main.mm", + ] + configs += [ "../../..:crashpad_config" ] + deps = [ + ":app_shared_sources", + "../../../build:ios_enable_arc", + "../../../third_party/edo", + ] + libs = [ + "Foundation.framework", + "UIKit.framework", + ] +} + +ios_app_bundle("ios_crash_xcuitests") { + info_plist = "Info.plist" + testonly = true + deps = [ + ":app_host_sources", + ] +} diff --git a/test/ios/host/Info.plist b/test/ios/host/Info.plist new file mode 100644 index 00000000..8944a2e4 --- /dev/null +++ b/test/ios/host/Info.plist @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleDisplayName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundleExecutable</key> + <string>${EXECUTABLE_NAME}</string> + <key>CFBundleIdentifier</key> + <string>${IOS_BUNDLE_ID_PREFIX}.gtest.${EXECUTABLE_NAME:rfc1034identifier}</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>UILaunchImages</key> + <array> + <dict> + <key>UILaunchImageMinimumOSVersion</key> + <string>9.0</string> + <key>UILaunchImageName</key> + <string>Default</string> + <key>UILaunchImageSize</key> + <string>{320, 480}</string> + </dict> + <dict> + <key>UILaunchImageMinimumOSVersion</key> + <string>9.0</string> + <key>UILaunchImageName</key> + <string>Default</string> + <key>UILaunchImageSize</key> + <string>{320, 568}</string> + </dict> + <dict> + <key>UILaunchImageMinimumOSVersion</key> + <string>9.0</string> + <key>UILaunchImageName</key> + <string>Default</string> + <key>UILaunchImageSize</key> + <string>{375, 667}</string> + </dict> + <dict> + <key>UILaunchImageMinimumOSVersion</key> + <string>9.0</string> + <key>UILaunchImageName</key> + <string>Default</string> + <key>UILaunchImageSize</key> + <string>{414, 736}</string> + </dict> + <dict> + <key>UILaunchImageMinimumOSVersion</key> + <string>9.0</string> + <key>UILaunchImageName</key> + <string>Default</string> + <key>UILaunchImageSize</key> + <string>{375, 812}</string> + </dict> + <dict> + <key>UILaunchImageMinimumOSVersion</key> + <string>9.0</string> + <key>UILaunchImageName</key> + <string>Default</string> + <key>UILaunchImageSize</key> + <string>{414, 896}</string> + </dict> + </array> + <key>UILaunchImages~ipad</key> + <array> + <dict> + <key>UILaunchImageMinimumOSVersion</key> + <string>9.0</string> + <key>UILaunchImageName</key> + <string>Default</string> + <key>UILaunchImageSize</key> + <string>{768, 1024}</string> + </dict> + <dict> + <key>UILaunchImageMinimumOSVersion</key> + <string>9.0</string> + <key>UILaunchImageName</key> + <string>Default</string> + <key>UILaunchImageSize</key> + <string>{1024, 1366}</string> + </dict> + <dict> + <key>UILaunchImageMinimumOSVersion</key> + <string>9.0</string> + <key>UILaunchImageName</key> + <string>Default</string> + <key>UILaunchImageSize</key> + <string>{832, 1114}</string> + </dict> + </array> + <key>UISupportedInterfaceOrientation</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> +</dict> +</plist> diff --git a/test/ios/host/application_delegate.h b/test/ios/host/application_delegate.h new file mode 100644 index 00000000..3405e7a8 --- /dev/null +++ b/test/ios/host/application_delegate.h @@ -0,0 +1,23 @@ +// 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_TEST_IOS_HOST_APPLICATION_DELEGATE_H_ +#define CRASHPAD_TEST_IOS_HOST_APPLICATION_DELEGATE_H_ + +#import <UIKit/UIKit.h> + +@interface ApplicationDelegate : UIResponder <UIApplicationDelegate> +@end + +#endif // CRASHPAD_TEST_IOS_HOST_APPLICATION_DELEGATE_H_ diff --git a/test/ios/host/application_delegate.mm b/test/ios/host/application_delegate.mm new file mode 100644 index 00000000..115d0ae5 --- /dev/null +++ b/test/ios/host/application_delegate.mm @@ -0,0 +1,53 @@ +// 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. + +#import "test/ios/host/application_delegate.h" + +#import "Service/Sources/EDOHostNamingService.h" +#import "Service/Sources/EDOHostService.h" +#import "test/ios/host/crash_view_controller.h" +#import "test/ios/host/edo_placeholder.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation ApplicationDelegate +@synthesize window = _window; + +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + [self.window makeKeyAndVisible]; + self.window.backgroundColor = UIColor.greenColor; + + CrashViewController* controller = [[CrashViewController alloc] init]; + self.window.rootViewController = controller; + + // Start up EDO. + [EDOHostService serviceWithPort:12345 + rootObject:[[EDOPlaceholder alloc] init] + queue:dispatch_get_main_queue()]; + [EDOHostNamingService.sharedService start]; + + return YES; +} + +@end + +@implementation EDOPlaceholder +- (NSString*)testEDO { + return @"crashpad"; +} +@end diff --git a/test/ios/host/crash_view_controller.h b/test/ios/host/crash_view_controller.h new file mode 100644 index 00000000..fdbdfc1a --- /dev/null +++ b/test/ios/host/crash_view_controller.h @@ -0,0 +1,23 @@ +// 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_TEST_IOS_HOST_CRASH_VIEW_CONTROLLER_H_ +#define CRASHPAD_TEST_IOS_HOST_CRASH_VIEW_CONTROLLER_H_ + +#import <UIKit/UIKit.h> + +@interface CrashViewController : UIViewController +@end + +#endif // CRASHPAD_TEST_IOS_HOST_CRASH_VIEW_CONTROLLER_H_ diff --git a/test/ios/host/crash_view_controller.mm b/test/ios/host/crash_view_controller.mm new file mode 100644 index 00000000..f8c05f76 --- /dev/null +++ b/test/ios/host/crash_view_controller.mm @@ -0,0 +1,33 @@ +// 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. + +#import "test/ios/host/crash_view_controller.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation CrashViewController + +- (void)loadView { + self.view = [[UIView alloc] init]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.redColor; +} + +@end diff --git a/test/ios/host/edo_placeholder.h b/test/ios/host/edo_placeholder.h new file mode 100644 index 00000000..84bf0c44 --- /dev/null +++ b/test/ios/host/edo_placeholder.h @@ -0,0 +1,24 @@ +// 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_TEST_IOS_HOST_EDO_PLACEHOLDER_H_ +#define CRASHPAD_TEST_IOS_HOST_EDO_PLACEHOLDER_H_ + +#import <UIKit/UIKit.h> + +@interface EDOPlaceholder : NSObject +- (NSString*)testEDO; +@end + +#endif // CRASHPAD_TEST_IOS_HOST_EDO_PLACEHOLDER_H_ diff --git a/test/ios/host/main.mm b/test/ios/host/main.mm new file mode 100644 index 00000000..932cd897 --- /dev/null +++ b/test/ios/host/main.mm @@ -0,0 +1,30 @@ +// 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. + +#import <UIKit/UIKit.h> + +#import "test/ios/host/application_delegate.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +int main(int argc, char* argv[]) { + NSString* appDelegateClassName; + @autoreleasepool { + // Setup code that might create autoreleased objects goes here. + appDelegateClassName = NSStringFromClass([ApplicationDelegate class]); + } + return UIApplicationMain(argc, argv, nil, appDelegateClassName); +} diff --git a/third_party/edo/BUILD.gn b/third_party/edo/BUILD.gn new file mode 100644 index 00000000..0205489f --- /dev/null +++ b/third_party/edo/BUILD.gn @@ -0,0 +1,142 @@ +# Copyright 2018 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. + +import("../../build/crashpad_buildconfig.gni") + +if (crashpad_is_in_chromium) { + group("edo") { + testonly = true + public_deps = [ + "//ios/third_party/edo", + ] + } +} else { + config("config") { + include_dirs = [ "../../third_party/edo/edo" ] + } + + source_set("edo") { + testonly = true + + sources = [ + "edo/Channel/Sources/EDOBlockingQueue.h", + "edo/Channel/Sources/EDOBlockingQueue.m", + "edo/Channel/Sources/EDOChannel.h", + "edo/Channel/Sources/EDOChannelErrors.h", + "edo/Channel/Sources/EDOChannelErrors.m", + "edo/Channel/Sources/EDOChannelForwarder.h", + "edo/Channel/Sources/EDOChannelForwarder.m", + "edo/Channel/Sources/EDOChannelMultiplexer.h", + "edo/Channel/Sources/EDOChannelMultiplexer.m", + "edo/Channel/Sources/EDOChannelPool.h", + "edo/Channel/Sources/EDOChannelPool.m", + "edo/Channel/Sources/EDOChannelUtil.h", + "edo/Channel/Sources/EDOChannelUtil.m", + "edo/Channel/Sources/EDOHostPort.h", + "edo/Channel/Sources/EDOHostPort.m", + "edo/Channel/Sources/EDOListenSocket.h", + "edo/Channel/Sources/EDOListenSocket.m", + "edo/Channel/Sources/EDOSocket.h", + "edo/Channel/Sources/EDOSocket.m", + "edo/Channel/Sources/EDOSocketChannel.h", + "edo/Channel/Sources/EDOSocketChannel.m", + "edo/Channel/Sources/EDOSocketPort.h", + "edo/Channel/Sources/EDOSocketPort.m", + "edo/Device/Sources/EDODeviceChannel.h", + "edo/Device/Sources/EDODeviceChannel.m", + "edo/Device/Sources/EDODeviceConnector.h", + "edo/Device/Sources/EDODeviceConnector.m", + "edo/Device/Sources/EDODeviceDetector.h", + "edo/Device/Sources/EDODeviceDetector.m", + "edo/Device/Sources/EDOUSBMuxUtil.h", + "edo/Device/Sources/EDOUSBMuxUtil.m", + "edo/DeviceForwarder/Sources/EDODeviceForwardersManager.h", + "edo/DeviceForwarder/Sources/EDODeviceForwardersManager.m", + "edo/Measure/Sources/EDONumericMeasure.h", + "edo/Measure/Sources/EDONumericMeasure.m", + "edo/Service/Sources/EDOBlockObject.h", + "edo/Service/Sources/EDOBlockObject.m", + "edo/Service/Sources/EDOClassMessage.h", + "edo/Service/Sources/EDOClassMessage.m", + "edo/Service/Sources/EDOClientService+Private.h", + "edo/Service/Sources/EDOClientService.h", + "edo/Service/Sources/EDOClientService.m", + "edo/Service/Sources/EDOClientServiceStatsCollector.h", + "edo/Service/Sources/EDOClientServiceStatsCollector.m", + "edo/Service/Sources/EDODeallocationTracker.h", + "edo/Service/Sources/EDODeallocationTracker.m", + "edo/Service/Sources/EDOExecutor.h", + "edo/Service/Sources/EDOExecutor.m", + "edo/Service/Sources/EDOExecutorMessage.h", + "edo/Service/Sources/EDOExecutorMessage.m", + "edo/Service/Sources/EDOHostNamingService+Private.h", + "edo/Service/Sources/EDOHostNamingService.h", + "edo/Service/Sources/EDOHostNamingService.m", + "edo/Service/Sources/EDOHostService+Handlers.h", + "edo/Service/Sources/EDOHostService+Handlers.m", + "edo/Service/Sources/EDOHostService+Private.h", + "edo/Service/Sources/EDOHostService.h", + "edo/Service/Sources/EDOHostService.m", + "edo/Service/Sources/EDOInvocationMessage.h", + "edo/Service/Sources/EDOInvocationMessage.m", + "edo/Service/Sources/EDOMessage.h", + "edo/Service/Sources/EDOMessage.m", + "edo/Service/Sources/EDOMethodSignatureMessage.h", + "edo/Service/Sources/EDOMethodSignatureMessage.m", + "edo/Service/Sources/EDOObject+EDOParameter.m", + "edo/Service/Sources/EDOObject+Invocation.m", + "edo/Service/Sources/EDOObject+Private.h", + "edo/Service/Sources/EDOObject.h", + "edo/Service/Sources/EDOObject.m", + "edo/Service/Sources/EDOObjectAliveMessage.h", + "edo/Service/Sources/EDOObjectAliveMessage.m", + "edo/Service/Sources/EDOObjectMessage.h", + "edo/Service/Sources/EDOObjectMessage.m", + "edo/Service/Sources/EDOObjectReleaseMessage.h", + "edo/Service/Sources/EDOObjectReleaseMessage.m", + "edo/Service/Sources/EDOParameter.h", + "edo/Service/Sources/EDOParameter.m", + "edo/Service/Sources/EDOProtocolObject.h", + "edo/Service/Sources/EDOProtocolObject.m", + "edo/Service/Sources/EDORemoteVariable.h", + "edo/Service/Sources/EDORemoteVariable.m", + "edo/Service/Sources/EDOServiceError.h", + "edo/Service/Sources/EDOServiceError.m", + "edo/Service/Sources/EDOServiceException.h", + "edo/Service/Sources/EDOServiceException.m", + "edo/Service/Sources/EDOServicePort.h", + "edo/Service/Sources/EDOServicePort.m", + "edo/Service/Sources/EDOServiceRequest.h", + "edo/Service/Sources/EDOServiceRequest.m", + "edo/Service/Sources/EDOTimingFunctions.h", + "edo/Service/Sources/EDOTimingFunctions.m", + "edo/Service/Sources/EDOValueObject+EDOParameter.m", + "edo/Service/Sources/EDOValueObject.h", + "edo/Service/Sources/EDOValueObject.m", + "edo/Service/Sources/EDOValueType.m", + "edo/Service/Sources/EDOWeakObject.h", + "edo/Service/Sources/EDOWeakObject.m", + "edo/Service/Sources/NSBlock+EDOInvocation.m", + "edo/Service/Sources/NSKeyedArchiver+EDOAdditions.h", + "edo/Service/Sources/NSKeyedArchiver+EDOAdditions.m", + "edo/Service/Sources/NSKeyedUnarchiver+EDOAdditions.h", + "edo/Service/Sources/NSKeyedUnarchiver+EDOAdditions.m", + "edo/Service/Sources/NSObject+EDOParameter.h", + "edo/Service/Sources/NSObject+EDOParameter.m", + "edo/Service/Sources/NSObject+EDOValue.h", + "edo/Service/Sources/NSObject+EDOValue.m", + "edo/Service/Sources/NSObject+EDOValueObject.h", + "edo/Service/Sources/NSObject+EDOValueObject.m", + "edo/Service/Sources/NSObject+EDOWeakObject.h", + "edo/Service/Sources/NSObject+EDOWeakObject.m", + "edo/Service/Sources/NSProxy+EDOParameter.h", + "edo/Service/Sources/NSProxy+EDOParameter.m", + ] + + public_configs = [ ":config" ] + deps = [ + "../../build:ios_enable_arc", + ] + } +} diff --git a/third_party/edo/README.crashpad b/third_party/edo/README.crashpad new file mode 100644 index 00000000..fb831582 --- /dev/null +++ b/third_party/edo/README.crashpad @@ -0,0 +1,10 @@ +Name: eDistantObject +Short Name: EDO +URL: https://github.com/google/eDistantObject +Revision: See DEPS +License: Apache 2.0 +License File: edo/LICENSE +Security Critical: no + +Description: +iOS remote method invocations (distant object) over Inter-process communication layer. diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index ae55259f..58197334 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -18,20 +18,28 @@ import("../../build/test.gni") if (crashpad_is_in_chromium) { group("gtest") { testonly = true - public_deps = [ "//testing/gtest" ] + public_deps = [ + "//testing/gtest", + ] } group("gmock") { testonly = true - public_deps = [ "//testing/gmock" ] + public_deps = [ + "//testing/gmock", + ] } } else if (crashpad_is_in_dart || crashpad_is_in_fuchsia) { group("gtest") { testonly = true - public_deps = [ "//third_party/googletest:gtest" ] + public_deps = [ + "//third_party/googletest:gtest", + ] } group("gmock") { testonly = true - public_deps = [ "//third_party/googletest:gmock" ] + public_deps = [ + "//third_party/googletest:gmock", + ] } } else if (crashpad_is_standalone) { config("gtest_private_config") { @@ -64,7 +72,6 @@ if (crashpad_is_in_chromium) { "gtest/googletest/include/gtest/internal/gtest-death-test-internal.h", "gtest/googletest/include/gtest/internal/gtest-filepath.h", "gtest/googletest/include/gtest/internal/gtest-internal.h", - "gtest/googletest/include/gtest/internal/gtest-param-util-generated.h", "gtest/googletest/include/gtest/internal/gtest-param-util.h", "gtest/googletest/include/gtest/internal/gtest-port-arch.h", "gtest/googletest/include/gtest/internal/gtest-port.h", @@ -88,7 +95,9 @@ if (crashpad_is_in_chromium) { ] configs += [ ":gtest_private_config" ] if (crashpad_is_fuchsia) { - deps = [ "../fuchsia" ] + deps = [ + "../fuchsia", + ] } } @@ -97,8 +106,12 @@ if (crashpad_is_in_chromium) { visibility = [ ":*" ] testonly = true - sources = [ "gtest/googletest/src/gtest_main.cc" ] - deps = [ ":gtest" ] + sources = [ + "gtest/googletest/src/gtest_main.cc", + ] + deps = [ + ":gtest", + ] } test("gtest_all_test") { @@ -136,19 +149,31 @@ if (crashpad_is_in_chromium) { } test("gtest_environment_test") { - sources = [ "gtest/googletest/test/gtest_environment_test.cc" ] + sources = [ + "gtest/googletest/test/gtest_environment_test.cc", + ] configs += [ ":gtest_private_config" ] - deps = [ ":gtest" ] + deps = [ + ":gtest", + ] } test("gtest_listener_test") { - sources = [ "gtest/googletest/test/googletest-listener-test.cc" ] - deps = [ ":gtest" ] + sources = [ + "gtest/googletest/test/googletest-listener-test.cc", + ] + deps = [ + ":gtest", + ] } test("gtest_no_test") { - sources = [ "gtest/googletest/test/gtest_no_test_unittest.cc" ] - deps = [ ":gtest" ] + sources = [ + "gtest/googletest/test/gtest_no_test_unittest.cc", + ] + deps = [ + ":gtest", + ] } test("gtest_param_test") { @@ -161,7 +186,9 @@ if (crashpad_is_in_chromium) { "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", ] configs += [ ":gtest_private_config" ] - deps = [ ":gtest" ] + deps = [ + ":gtest", + ] if (crashpad_is_clang) { cflags_cc = [ @@ -173,18 +200,28 @@ if (crashpad_is_in_chromium) { } test("gtest_premature_exit_test") { - sources = [ "gtest/googletest/test/gtest_premature_exit_test.cc" ] - deps = [ ":gtest" ] + sources = [ + "gtest/googletest/test/gtest_premature_exit_test.cc", + ] + deps = [ + ":gtest", + ] } test("gtest_repeat_test") { - sources = [ "gtest/googletest/test/gtest_repeat_test.cc" ] + sources = [ + "gtest/googletest/test/gtest_repeat_test.cc", + ] configs += [ ":gtest_private_config" ] - deps = [ ":gtest" ] + deps = [ + ":gtest", + ] } test("gtest_sole_header_test") { - sources = [ "gtest/googletest/test/gtest_sole_header_test.cc" ] + sources = [ + "gtest/googletest/test/gtest_sole_header_test.cc", + ] deps = [ ":gtest", ":gtest_main", @@ -192,14 +229,22 @@ if (crashpad_is_in_chromium) { } test("gtest_stress_test") { - sources = [ "gtest/googletest/test/gtest_stress_test.cc" ] + sources = [ + "gtest/googletest/test/gtest_stress_test.cc", + ] configs += [ ":gtest_private_config" ] - deps = [ ":gtest" ] + deps = [ + ":gtest", + ] } test("gtest_unittest_api_test") { - sources = [ "gtest/googletest/test/gtest-unittest-api_test.cc" ] - deps = [ ":gtest" ] + sources = [ + "gtest/googletest/test/gtest-unittest-api_test.cc", + ] + deps = [ + ":gtest", + ] } group("gtest_all_tests") { @@ -256,7 +301,6 @@ if (crashpad_is_in_chromium) { "gtest/googlemock/include/gmock/internal/custom/gmock-generated-actions.h", "gtest/googlemock/include/gmock/internal/custom/gmock-matchers.h", "gtest/googlemock/include/gmock/internal/custom/gmock-port.h", - "gtest/googlemock/include/gmock/internal/gmock-generated-internal-utils.h", "gtest/googlemock/include/gmock/internal/gmock-internal-utils.h", "gtest/googlemock/include/gmock/internal/gmock-port.h", "gtest/googlemock/include/gmock/internal/gmock-pp.h", @@ -273,14 +317,18 @@ if (crashpad_is_in_chromium) { "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", ] configs += [ ":gmock_private_config" ] - deps = [ ":gtest" ] + deps = [ + ":gtest", + ] } static_library("gmock_main") { # Tests outside of this file should use ../../test:gmock_main instead. visibility = [ ":*" ] testonly = true - sources = [ "gtest/googlemock/src/gmock_main.cc" ] + sources = [ + "gtest/googlemock/src/gmock_main.cc", + ] deps = [ ":gmock", ":gtest", @@ -339,7 +387,9 @@ if (crashpad_is_in_chromium) { } test("gmock_stress_test") { - sources = [ "gtest/googlemock/test/gmock_stress_test.cc" ] + sources = [ + "gtest/googlemock/test/gmock_stress_test.cc", + ] configs -= [ "//third_party/mini_chromium/mini_chromium/build:Wexit_time_destructors", ] From 3b007333a0fa014ef8842a4017a318fb5c6fa86b Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Fri, 31 Jan 2020 12:58:37 -0500 Subject: [PATCH 321/401] Roll crashpad/third_party/mini_chromium/mini_chromium/ f58366399..0a3a80b04 (2 commits) https://chromium.googlesource.com/chromium/mini_chromium/+log/f58366399b4e..0a3a80b04b3f $ git log f58366399..0a3a80b04 --date=short --no-merges --format='%ad %ae %s' 2020-01-31 rohitrao Adds support for ios_xctest_test. 2020-01-31 justincohen Sign iOS apps on simulator too. Created with: roll-dep crashpad/third_party/mini_chromium/mini_chromium R=0a3a80b04b3f8b1268877fd376954a8af1480171@chromium.org Bug: crashpad:317 Change-Id: I3dedbb7cde03245fbcdacefae41a0f5fb965859d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2033430 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 6e4ac6d8..2f882900 100644 --- a/DEPS +++ b/DEPS @@ -42,7 +42,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'f58366399b4e50413773fbb2f9a1a5e7289462c1', + '0a3a80b04b3f8b1268877fd376954a8af1480171', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 39116ab7230c28854c711471e66360d5a4cefe56 Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Fri, 31 Jan 2020 14:51:39 -0500 Subject: [PATCH 322/401] Adds support for running iOS unittests via XCTest. Using XCTest allows us to drive tests from the commandline via xcodebuild, and it also simplifies running tests on physical devices. Tests put themselves into "XCTest-mode" if the "XCTestConfigurationFilePath" environment variable is present. This variable is only set when XCTests are running. Change-Id: If55199a7470f0479f107097eef1dfb1a705015e9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2033427 Commit-Queue: Rohit Rao <rohitrao@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- build/test.gni | 3 +- test/BUILD.gn | 17 +------- test/gtest_main.cc | 2 +- test/ios/BUILD.gn | 39 +++++++++++++++--- test/ios/cptest_google_test_runner.mm | 41 +++++++++++++++++++ test/ios/cptest_google_test_runner_delegate.h | 30 ++++++++++++++ .../google_test_setup.h} | 6 +-- .../google_test_setup.mm} | 35 ++++++++++++---- 8 files changed, 140 insertions(+), 33 deletions(-) create mode 100644 test/ios/cptest_google_test_runner.mm create mode 100644 test/ios/cptest_google_test_runner_delegate.h rename test/{gtest_runner_ios.h => ios/google_test_setup.h} (89%) rename test/{gtest_runner_ios.mm => ios/google_test_setup.mm} (79%) diff --git a/build/test.gni b/build/test.gni index 867b7730..01fd7e79 100644 --- a/build/test.gni +++ b/build/test.gni @@ -28,8 +28,9 @@ if (crashpad_is_in_chromium) { outputs = [ "{{bundle_contents_dir}}/{{source_file_part}}" ] } - ios_app_bundle(target_name) { + ios_xctest_test(target_name) { testonly = true + xctest_module_target = "//test/ios:google_test_runner" info_plist = "//build/ios/Unittest-Info.plist" extra_substitutions = [ "GTEST_BUNDLE_ID_SUFFIX=$target_name" ] forward_variables_from(invoker, "*") diff --git a/test/BUILD.gn b/test/BUILD.gn index e71ae246..a00f682f 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -233,19 +233,6 @@ if (!crashpad_is_ios) { } } -if (crashpad_is_ios) { - source_set("test_runner_ios") { - testonly = true - sources = [ - "gtest_runner_ios.h", - "gtest_runner_ios.mm", - ] - configs += [ "..:crashpad_config" ] - deps = [ "../third_party/gtest:gtest" ] - libs = [ "UIKit.framework" ] - } -} - static_library("gmock_main") { testonly = true sources = [ "gtest_main.cc" ] @@ -259,7 +246,7 @@ static_library("gmock_main") { "../third_party/mini_chromium:base_test_support", ] if (crashpad_is_ios) { - deps += [ ":test_runner_ios" ] + deps += [ "ios:google_test_setup" ] } } @@ -275,6 +262,6 @@ static_library("gtest_main") { "../third_party/mini_chromium:base_test_support", ] if (crashpad_is_ios) { - deps += [ ":test_runner_ios" ] + deps += [ "ios:google_test_setup" ] } } diff --git a/test/gtest_main.cc b/test/gtest_main.cc index f6b6a69e..34394ad4 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -22,7 +22,7 @@ #endif // CRASHPAD_TEST_LAUNCHER_GMOCK #if defined(OS_IOS) -#include "test/gtest_runner_ios.h" +#include "test/ios/google_test_setup.h" #endif #if defined(OS_WIN) diff --git a/test/ios/BUILD.gn b/test/ios/BUILD.gn index 722c4cae..225bf2a2 100644 --- a/test/ios/BUILD.gn +++ b/test/ios/BUILD.gn @@ -28,12 +28,43 @@ group("all_tests") { ] } -source_set("xcuitests") { +source_set("google_test_runner_shared_headers") { + testonly = true + sources = [ "cptest_google_test_runner_delegate.h" ] +} + +source_set("google_test_runner") { + testonly = true + sources = [ "cptest_google_test_runner.mm" ] + configs += [ "../..:crashpad_config" ] + deps = [ + "../../build:ios_enable_arc", + "../../build:ios_xctest", + "../../third_party/mini_chromium:base", + ] + libs = [ "UIKit.framework" ] +} + +source_set("google_test_setup") { testonly = true sources = [ - "crash_type_xctest.mm", + "google_test_setup.h", + "google_test_setup.mm", ] configs += [ "../..:crashpad_config" ] + deps = [ + ":google_test_runner_shared_headers", + "../../build:ios_enable_arc", + "../../third_party/gtest:gtest", + "../../third_party/mini_chromium:base", + ] + libs = [ "UIKit.framework" ] +} + +source_set("xcuitests") { + testonly = true + sources = [ "crash_type_xctest.mm" ] + configs += [ "../..:crashpad_config" ] deps = [ "../../build:ios_enable_arc", "../../build:ios_xctest", @@ -44,7 +75,5 @@ source_set("xcuitests") { ios_xcuitest_test("ios_crash_xcuitests_module") { xcode_test_application_name = "ios_crash_xcuitests" - deps = [ - ":xcuitests", - ] + deps = [ ":xcuitests" ] } diff --git a/test/ios/cptest_google_test_runner.mm b/test/ios/cptest_google_test_runner.mm new file mode 100644 index 00000000..ae933fcc --- /dev/null +++ b/test/ios/cptest_google_test_runner.mm @@ -0,0 +1,41 @@ +// 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. + +#import <UIKit/UIKit.h> +#import <XCTest/XCTest.h> + +#include "base/logging.h" +#import "test/ios/cptest_google_test_runner_delegate.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface CPTestGoogleTestRunner : XCTestCase +@end + +@implementation CPTestGoogleTestRunner + +- (void)testRunGoogleTests { + id appDelegate = UIApplication.sharedApplication.delegate; + DCHECK([appDelegate + conformsToProtocol:@protocol(CPTestGoogleTestRunnerDelegate)]); + + id<CPTestGoogleTestRunnerDelegate> runnerDelegate = + static_cast<id<CPTestGoogleTestRunnerDelegate>>(appDelegate); + DCHECK(runnerDelegate.supportsRunningGoogleTestsWithXCTest); + XCTAssertTrue([runnerDelegate runGoogleTests] == 0); +} + +@end diff --git a/test/ios/cptest_google_test_runner_delegate.h b/test/ios/cptest_google_test_runner_delegate.h new file mode 100644 index 00000000..f88d63de --- /dev/null +++ b/test/ios/cptest_google_test_runner_delegate.h @@ -0,0 +1,30 @@ +// 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_TEST_IOS_CPTEST_GOOGLE_TEST_RUNNER_DELEGATE_ +#define CRASHPAD_TEST_IOS_CPTEST_GOOGLE_TEST_RUNNER_DELEGATE_ + +@protocol CPTestGoogleTestRunnerDelegate + +// Returns YES if this delegate supports running GoogleTests via a call to +// |runGoogleTests|. +@property(nonatomic, readonly, assign) + BOOL supportsRunningGoogleTestsWithXCTest; + +// Runs GoogleTests and returns the final exit code. +- (int)runGoogleTests; + +@end + +#endif // CRASHPAD_TEST_IOS_CPTEST_GOOGLE_TEST_RUNNER_DELEGATE_H_ diff --git a/test/gtest_runner_ios.h b/test/ios/google_test_setup.h similarity index 89% rename from test/gtest_runner_ios.h rename to test/ios/google_test_setup.h index 564fe5c2..98bb9427 100644 --- a/test/gtest_runner_ios.h +++ b/test/ios/google_test_setup.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CRASHPAD_TEST_GTEST_RUNNER_IOS_ -#define CRASHPAD_TEST_GTEST_RUNNER_IOS_ +#ifndef CRASHPAD_TEST_IOS_GOOGLE_TEST_SETUP_ +#define CRASHPAD_TEST_IOS_GOOGLE_TEST_SETUP_ namespace crashpad { namespace test { @@ -30,4 +30,4 @@ void IOSLaunchApplicationAndRunTests(int argc, char* argv[]); } // namespace test } // namespace crashpad -#endif // CRASHPAD_TEST_GTEST_RUNNER_IOS_ +#endif // CRASHPAD_TEST_IOS_GOOGLE_TEST_SETUP_ diff --git a/test/gtest_runner_ios.mm b/test/ios/google_test_setup.mm similarity index 79% rename from test/gtest_runner_ios.mm rename to test/ios/google_test_setup.mm index 8738fcb9..b2211903 100644 --- a/test/gtest_runner_ios.mm +++ b/test/ios/google_test_setup.mm @@ -12,11 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "test/gtest_runner_ios.h" +#include "test/ios/google_test_setup.h" #import <UIKit/UIKit.h> +#include "base/logging.h" #include "gtest/gtest.h" +#include "test/ios/cptest_google_test_runner_delegate.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif @interface UIApplication (Testing) - (void)_terminateWithStatus:(int)status; @@ -47,7 +53,7 @@ void RegisterTestEndListener() { } // namespace -@interface CrashpadUnitTestDelegate : NSObject +@interface CrashpadUnitTestDelegate : NSObject <CPTestGoogleTestRunnerDelegate> @property(nonatomic, readwrite, strong) UIWindow* window; - (void)runTests; @end @@ -71,15 +77,29 @@ void RegisterTestEndListener() { [controller.view addSubview:label]; // Queue up the test run. - [self performSelector:@selector(runTests) withObject:nil afterDelay:0.1]; + if (![self supportsRunningGoogleTestsWithXCTest]) { + // When running in XCTest mode, XCTest will invoke |runGoogleTest| directly. + // Otherwise, schedule a call to |runTests|. + [self performSelector:@selector(runTests) withObject:nil afterDelay:0.1]; + } return YES; } -- (void)runTests { - RegisterTestEndListener(); +- (BOOL)supportsRunningGoogleTestsWithXCTest { + return getenv("XCTestConfigurationFilePath") != nullptr; +} +- (int)runGoogleTests { + RegisterTestEndListener(); int exitStatus = RUN_ALL_TESTS(); + return exitStatus; +} + +- (void)runTests { + DCHECK(![self supportsRunningGoogleTestsWithXCTest]); + + int exitStatus = [self runGoogleTests]; // If a test app is too fast, it will exit before Instruments has has a // a chance to initialize and no test results will be seen. @@ -98,7 +118,6 @@ void RegisterTestEndListener() { @end - namespace crashpad { namespace test { @@ -110,5 +129,5 @@ void IOSLaunchApplicationAndRunTests(int argc, char* argv[]) { } } -} // namespace crashpad -} // namespace test +} // namespace test +} // namespace crashpad From 46ad005e9265e6c2b99f9359ea65db4c8e411313 Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Fri, 31 Jan 2020 15:29:32 -0500 Subject: [PATCH 323/401] Updates run_tests.py to support testing on iOS. Tests are run by creating an xctestrun file in a temp directory and then invoking "xcodebuild test-without-building". Tests run on the latest OS version (the default for the running version of Xcode) on iPhone X. Bug: crashpad:317 Change-Id: If9f34f8798fd4c2a02fecca180913e8f86011304 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2033606 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- build/run_tests.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/build/run_tests.py b/build/run_tests.py index 29fd3c1b..44620fb8 100755 --- a/build/run_tests.py +++ b/build/run_tests.py @@ -24,6 +24,7 @@ import posixpath import re import subprocess import sys +import tempfile import uuid CRASHPAD_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), @@ -435,6 +436,68 @@ def _RunOnFuchsiaTarget(binary_dir, test, device_name, extra_command_line): netruncmd(['rm', '-rf', test_root]) +def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False): + """Runs the given iOS |test| app on iPhone X with the default OS version.""" + + def xctest(binary_dir, test): + """Returns a dict containing the xctestrun data needed to run an + XCTest-based test app.""" + test_path = os.path.join(CRASHPAD_DIR, binary_dir) + module_data = { + 'TestBundlePath': os.path.join(test_path, test + '_module.xctest'), + 'TestHostPath': os.path.join(test_path, test + '.app'), + 'TestingEnvironmentVariables': { + 'DYLD_FRAMEWORK_PATH': '__TESTROOT__/Debug-iphonesimulator:', + 'DYLD_INSERT_LIBRARIES': ( + '__PLATFORMS__/iPhoneSimulator.platform/Developer/' + 'usr/lib/libXCTestBundleInject.dylib'), + 'DYLD_LIBRARY_PATH': '__TESTROOT__/Debug-iphonesimulator', + 'IDEiPhoneInternalTestBundleName': test + '.app', + 'XCInjectBundleInto': '__TESTHOST__/' + test, + } + } + return { test: module_data } + + def xcuitest(binary_dir, test): + """Returns a dict containing the xctestrun data needed to run an + XCUITest-based test app.""" + + test_path = os.path.join(CRASHPAD_DIR, binary_dir) + runner_path = os.path.join(test_path, test + '_module-Runner.app') + bundle_path = os.path.join(runner_path, 'PlugIns', test + '_module.xctest') + target_app_path = os.path.join(test_path, test + '.app') + module_data = { + 'IsUITestBundle': True, + 'IsXCTRunnerHostedTestBundle': True, + 'TestBundlePath': bundle_path, + 'TestHostPath': runner_path, + 'UITargetAppPath': target_app_path, + 'DependentProductPaths': [ bundle_path, runner_path, target_app_path ], + 'TestingEnvironmentVariables': { + 'DYLD_FRAMEWORK_PATH': '__TESTROOT__/Debug-iphonesimulator:', + 'DYLD_INSERT_LIBRARIES': ( + '__PLATFORMS__/iPhoneSimulator.platform/Developer/' + 'usr/lib/libXCTestBundleInject.dylib'), + 'DYLD_LIBRARY_PATH': '__TESTROOT__/Debug-iphonesimulator', + 'XCInjectBundleInto': '__TESTHOST__/' + test + '_module-Runner', + }, + } + return { test: module_data } + + with tempfile.NamedTemporaryFile() as f: + import plistlib + + 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) + + subprocess.check_call(['xcodebuild', 'test-without-building', + '-xctestrun', xctestrun_path, '-destination', + 'platform=iOS Simulator,name=iPhone X']) + # This script is primarily used from the waterfall so that the list of tests # that are run is maintained in-tree, rather than in a separate infrastructure # location in the recipe. @@ -461,6 +524,7 @@ def main(args): target_os = _BinaryDirTargetOS(args.binary_dir) is_android = target_os == 'android' is_fuchsia = target_os == 'fuchsia' + is_ios = target_os == 'ios' tests = [ 'crashpad_client_test', @@ -504,6 +568,8 @@ def main(args): print('Using autodetected Fuchsia device:', zircon_nodename) _GenerateFuchsiaRuntimeDepsFiles( args.binary_dir, [t for t in tests if not t.endswith('.py')]) + elif is_ios: + tests.append('ios_crash_xcuitests') elif IS_WINDOWS_HOST: tests.append('snapshot/win/end_to_end_test.py') @@ -531,6 +597,9 @@ def main(args): elif is_fuchsia: _RunOnFuchsiaTarget(args.binary_dir, test, zircon_nodename, extra_command_line) + elif is_ios: + _RunOnIOSTarget(args.binary_dir, test, + is_xcuitest=test.startswith('ios')) else: subprocess.check_call([os.path.join(args.binary_dir, test)] + extra_command_line) From e386d703d60d7de57521239f5dea5dd024f91d7a Mon Sep 17 00:00:00 2001 From: Tao Bai <michaelbai@chromium.org> Date: Fri, 31 Jan 2020 13:25:29 -0800 Subject: [PATCH 324/401] Fix typo in handler_main Bug: crashpad:308 Change-Id: I1b8124a8ad7c66376ce1c028959f11d5e84c7121 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2033431 Commit-Queue: Tao Bai <michaelbai@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> --- handler/handler_main.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 81c9a00a..e0a262cd 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -1004,6 +1004,8 @@ int HandlerMain(int argc, database.get(), static_cast<CrashReportUploadThread*>(upload_thread.Get()), &options.annotations, + true, + false, user_stream_sources); } #else @@ -1023,9 +1025,8 @@ int HandlerMain(int argc, true, false, #endif // OS_LINUX -#endif // OS_CHROMEOS user_stream_sources); - +#endif // OS_CHROMEOS #if defined(OS_LINUX) || defined(OS_ANDROID) if (options.exception_information_address) { From 39a319d6a7a9facfafce7bb6f2eb7cd15d873488 Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Fri, 31 Jan 2020 15:44:28 -0500 Subject: [PATCH 325/401] Roll buildtools/ 3e50219fc..62f9eb0d6 (8 commits) https://chromium.googlesource.com/chromium/src/buildtools.git/+log/3e50219fc450..62f9eb0d64d6 $ git log 3e50219fc..62f9eb0d6 --date=short --no-merges --format='%ad %ae %s' 2019-03-15 dpranke Add presubmit checks for //buildtools/DEPS entries. 2019-03-14 thomasanderson Clean up visibility for lib{c++,c++abi,unwind} and common_deps targets 2019-03-13 wez Revert "Move fuchsia libunwind dependency to common_deps" 2019-03-13 dpranke Reformat DEPS files to use single-quotes consistently. 2019-03-13 thomasanderson Correct libcxx{abi} revision in buildtools/DEPS 2019-03-13 thomasanderson Move fuchsia libunwind dependency to common_deps 2019-03-11 thomasanderson Roll libc++ to 355829 2019-03-06 thomasanderson Roll libc++ to 22d3f6dd Created with: roll-dep buildtools This rolls buildtools to the commit just before GN switched from GCS to CIPD. In a followup, I'll roll one more commit and switch crashpad to pulling GN via CIPD. Change-Id: I11081716d76cb18df5f1475ddcb8e58dc069a7f4 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2033607 Commit-Queue: Rohit Rao <rohitrao@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 2f882900..83deff04 100644 --- a/DEPS +++ b/DEPS @@ -25,7 +25,7 @@ vars = { deps = { 'buildtools': Var('chromium_git') + '/chromium/src/buildtools.git@' + - '3e50219fc4503f461b2176a9976891b28d80f9ab', + '62f9eb0d64d6bf48f620b8233d9f7a1dc07f8414', 'crashpad/third_party/edo/edo': { 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + '243fc89ae95b24717d41f3786f6a9abeeef87c92', From 56ec176fda7f1372a0639e856d0ad0c55d657961 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Mon, 3 Feb 2020 13:23:09 -0500 Subject: [PATCH 326/401] Fix Chromium checkperms.py has shebang but not executable bit error. Change-Id: I0fc5d853a38f186bba9937d537a95db37e0604ac Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2032978 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- build/ios/convert_gn_xcodeproj.py | 0 build/ios/setup-ios-gn.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build/ios/convert_gn_xcodeproj.py mode change 100644 => 100755 build/ios/setup-ios-gn.py diff --git a/build/ios/convert_gn_xcodeproj.py b/build/ios/convert_gn_xcodeproj.py old mode 100644 new mode 100755 diff --git a/build/ios/setup-ios-gn.py b/build/ios/setup-ios-gn.py old mode 100644 new mode 100755 From b97e77bcf521d358fa8dde13c4a5b673f4da6997 Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Mon, 3 Feb 2020 14:38:31 -0500 Subject: [PATCH 327/401] Roll buildtools/ 62f9eb0d6..eda23acab (11 commits; 2 trivial rolls) https://chromium.googlesource.com/chromium/src/buildtools.git/+log/62f9eb0d64d6..eda23acabd9a $ git log 62f9eb0d6..eda23acab --date=short --no-merges --format='%ad %ae %s' 2019-03-28 dpranke Roll GN from r1496 (0790d304) to r1546 (b85982b3) 2019-03-27 thomasanderson Enable in-tree libc++ builds on iOS 2019-03-27 raul Support Python 3 in //buildtools/ensure_gn_version.py 2019-03-22 dpranke Add ensure_gn_version.py and DEPS hook. 2019-03-20 thomasanderson Roll libc++ to r356574 2019-03-19 tikuta [buildtools] update .gitignore for CIPD 2019-03-18 olivierrobin Fetch gn based on the host OS. 2019-03-15 thomasanderson Set WINVER to WIN7 for libc++ 2019-03-15 dpranke Use CIPD packages for GN instead of GCS. Created with: roll-dep buildtools This rolls buildtools to a commit that pulls GN via CIPD and updates DEPS to stop downloading GN from GCS. Change-Id: Ic148c5ef380168ced0f8390668dcbf0a610304ba Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2036530 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- DEPS | 41 +---------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/DEPS b/DEPS index 83deff04..6ab6e1ad 100644 --- a/DEPS +++ b/DEPS @@ -25,7 +25,7 @@ vars = { deps = { 'buildtools': Var('chromium_git') + '/chromium/src/buildtools.git@' + - '62f9eb0d64d6bf48f620b8233d9f7a1dc07f8414', + 'eda23acabd9a73b6ddadcdd626c05a85d93d31dd', 'crashpad/third_party/edo/edo': { 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + '243fc89ae95b24717d41f3786f6a9abeeef87c92', @@ -177,45 +177,6 @@ hooks = [ 'buildtools/win/clang-format.exe.sha1', ], }, - { - 'name': 'gn_mac', - 'pattern': '.', - 'condition': 'host_os == "mac"', - 'action': [ - 'download_from_google_storage', - '--no_resume', - '--no_auth', - '--bucket=chromium-gn', - '--sha1_file', - 'buildtools/mac/gn.sha1', - ], - }, - { - 'name': 'gn_linux', - 'pattern': '.', - 'condition': 'host_os == "linux"', - 'action': [ - 'download_from_google_storage', - '--no_resume', - '--no_auth', - '--bucket=chromium-gn', - '--sha1_file', - 'buildtools/linux64/gn.sha1', - ], - }, - { - 'name': 'gn_win', - 'pattern': '.', - 'condition': 'host_os == "win"', - 'action': [ - 'download_from_google_storage', - '--no_resume', - '--no_auth', - '--bucket=chromium-gn', - '--sha1_file', - 'buildtools/win/gn.exe.sha1', - ], - }, { # If using a local clang ("pull_linux_clang" above), also pull down a # sysroot. From c094a11582f0788c50bc80bf6cb5a6e39f154f1b Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Mon, 3 Feb 2020 15:35:50 -0500 Subject: [PATCH 328/401] Roll buildtools/ eda23acab..6b3e658d6 (29 commits; 6 trivial rolls) https://chromium.googlesource.com/chromium/src/buildtools.git/+log/eda23acabd9a..6b3e658d6fe8 $ git log eda23acab..6b3e658d6 --date=short --no-merges --format='%ad %ae %s' 2019-11-18 xiaohuic Reland: Roll src/buildtools/third_party/libc++/trunk/ 5938e0582..78d6a7767 (333 commits) 2019-10-28 xiaohuic Revert "Roll src/buildtools/third_party/libc++/trunk/ 5938e0582..78d6a7767 (333 commits)" 2019-09-13 hnakashima Add exception for libassistant to import checker. 2019-09-10 dpranke Add a COMPONENT entry (Build) for //buildtools. 2019-09-10 dpranke Roll GN from 152c5144..ad9e442d 2019-07-25 thomasanderson List natvis files as inputs 2019-07-23 tikuta Roll GN from 972ed755 to 152c5144 2019-07-19 tsniatowski ensure_gn_version.py: don't die if existing gn is very old 2019-07-16 bratell Before trying to overwrite the gn binary, make it writable 2019-07-12 vapier ensure_gn_version.py: reinstall if tool is missing 2019-07-11 vapier ensure_gn_version.py: fix exception printing 2019-06-24 brettw Roll GN from 8c7f4910 to 972ed755 2019-06-21 thomasanderson Reland "Roll GN from 81ee1967 to 8c7f4910" 2019-06-17 sdy Revert "Roll GN from 81ee1967 to 8c7f4910" 2019-06-16 thomasanderson Roll GN from 81ee1967 to 8c7f4910 2019-06-14 mstensho Revert "Roll src/buildtools/third_party/libc++/trunk/ 5938e0582..ad464887b (53 commits)" 2019-06-13 mstensho Revert "Roll src/buildtools/third_party/libc++/trunk/ 5938e0582..78822a685 (48 commits)" 2019-06-07 oysteine Tracing: Moved the tracing sampling profiler to the tracing service 2019-05-23 wychen Exclude AndroidStudioDefault folder in Java import checking 2019-05-19 rsesek Roll GN from 64b846c9 to 81ee1967. 2019-05-13 jbudorick checkdeps: encode input to os.walk as utf-8. 2019-04-03 tikuta Roll GN from r1496 (0790d304) to r1555 (64b846c9) 2019-03-29 dpranke Revert "Roll GN from r1496 (0790d304) to r1546 (b85982b3)" Created with: roll-dep buildtools Change-Id: I9d0c41177307af404768d3c4e8909364f7fa6a3e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2036534 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 6ab6e1ad..6583c020 100644 --- a/DEPS +++ b/DEPS @@ -25,7 +25,7 @@ vars = { deps = { 'buildtools': Var('chromium_git') + '/chromium/src/buildtools.git@' + - 'eda23acabd9a73b6ddadcdd626c05a85d93d31dd', + '6b3e658d6fe8cd9c2588796d296f07312b776054', 'crashpad/third_party/edo/edo': { 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + '243fc89ae95b24717d41f3786f6a9abeeef87c92', From e9885ee3480aa4ee8f6b741b8cdf133c017ed6ec Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Tue, 4 Feb 2020 14:44:05 -0500 Subject: [PATCH 329/401] Roll crashpad/third_party/mini_chromium/mini_chromium/ 0a3a80b04..f8f1182ad (1 commit) https://chromium.googlesource.com/chromium/mini_chromium/+log/0a3a80b04b3f..f8f1182adb80 $ git log 0a3a80b04..f8f1182ad --date=short --no-merges --format='%ad %ae %s' 2020-02-04 rohitrao Explicitly specify lib_switch and lib_dir_switch in the msvc toolchain. Created with: roll-dep crashpad/third_party/mini_chromium/mini_chromium Change-Id: Id587cccedc77f26625d6d89a2205130db5b4ca43 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2037750 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 6583c020..fa5edcda 100644 --- a/DEPS +++ b/DEPS @@ -42,7 +42,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '0a3a80b04b3f8b1268877fd376954a8af1480171', + 'f8f1182adb804675b2aa4fb3ce03f6f884fae474', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From cad958a83367637f709c2ec7b65be1c3570c6960 Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Tue, 4 Feb 2020 14:46:39 -0500 Subject: [PATCH 330/401] Roll buildtools/ 6b3e658d6..afc5b798c (9 commits) https://chromium.googlesource.com/chromium/src/buildtools.git/+log/6b3e658d6fe8..afc5b798c729 $ git log 6b3e658d6..afc5b798c --date=short --no-merges --format='%ad %ae %s' 2020-01-28 thakis Roll GN 83dad00a:97cc440d 2020-01-28 thakis Reformat remaining gn files. 2020-01-21 sdefresne Roll GN 0c5557d173..83dad00afb 2020-01-16 thakis Reformat all gn files in /buildtools/third_party/libc++. 2020-01-16 felipesalazar Include cxa_thread_atexit on linux targets. 2020-01-13 thakis Roll GN a5bcbd726a..0c5557d17 2020-01-08 bpastene Update //buildtools/README.txt after it was merged into chromium. 2019-12-31 agable Roll GN from 6feb5599..a5bcbd72 2019-12-13 chouinard Roll GN from ad9e442d..6feb5599 Created with: roll-dep buildtools Change-Id: Ifdfa2dae072115c18ce859620ed01743cac312f9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2036509 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index fa5edcda..21dc3f0f 100644 --- a/DEPS +++ b/DEPS @@ -25,7 +25,7 @@ vars = { deps = { 'buildtools': Var('chromium_git') + '/chromium/src/buildtools.git@' + - '6b3e658d6fe8cd9c2588796d296f07312b776054', + 'afc5b798c72905e85f9991152be878714c579958', 'crashpad/third_party/edo/edo': { 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + '243fc89ae95b24717d41f3786f6a9abeeef87c92', From 5779e638e129c89d49e24959ef25d0dc40502658 Mon Sep 17 00:00:00 2001 From: Ian Barkley-Yeung <iby@chromium.org> Date: Thu, 6 Feb 2020 14:55:01 -0800 Subject: [PATCH 331/401] Note that uploads consent is ignored on ChromeOS Note that upload consent is ignored if --use-cros-crash-reporter is present, which it will be if invoked by Chrome on ChromeOS. BUG=chromium:1037656 TEST=None Change-Id: I2dcea736de40a082b477f21d46c3ed01f1d91699 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2042317 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Ian Barkley-Yeung <iby@chromium.org> --- client/settings.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/settings.h b/client/settings.h index a2b0c746..5761c6b9 100644 --- a/client/settings.h +++ b/client/settings.h @@ -75,6 +75,10 @@ class Settings { //! //! The default value is `false`. //! + //! \note + //! This setting is ignored if --use-cros-crash-reporter is present + //! (which it will be if invoked by Chrome on ChromeOS). + //! //! \param[out] enabled Whether crash reports should be uploaded. //! //! \return On success, returns `true`, otherwise returns `false` with an From 52ddeac77c3ae23bcfd717eb4445ac583d59666e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wilken=20D=C3=B6rrie?= <jdoerrie@chromium.org> Date: Fri, 7 Feb 2020 15:05:21 +0100 Subject: [PATCH 332/401] Don't implicitly construct StringPiece from nullptr This change implements the crashpad changes from https://crrev.com/c/2027791 upstream. Bug: chromium:1049498 Change-Id: I59b920d878b080d41db32bf0305d3d8f3d4f47c9 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2042712 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/simple_string_dictionary_test.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/simple_string_dictionary_test.cc b/client/simple_string_dictionary_test.cc index 7af51a27..cd23216c 100644 --- a/client/simple_string_dictionary_test.cc +++ b/client/simple_string_dictionary_test.cc @@ -73,7 +73,7 @@ TEST(SimpleStringDictionary, SimpleStringDictionary) { EXPECT_FALSE(dict.GetValueForKey("key3")); // Remove by setting value to nullptr - dict.SetKeyValue("key2", nullptr); + dict.SetKeyValue("key2", base::StringPiece(nullptr, 0)); // Now make sure it's not there anymore EXPECT_FALSE(dict.GetValueForKey("key2")); @@ -254,13 +254,14 @@ TEST(SimpleStringDictionary, OutOfSpace) { TEST(SimpleStringDictionaryDeathTest, SetKeyValueWithNullKey) { TSimpleStringDictionary<4, 6, 6> map; - ASSERT_DEATH_CHECK(map.SetKeyValue(nullptr, "hello"), "key"); + ASSERT_DEATH_CHECK(map.SetKeyValue(base::StringPiece(nullptr, 0), "hello"), + "key"); } TEST(SimpleStringDictionaryDeathTest, GetValueForKeyWithNullKey) { TSimpleStringDictionary<4, 6, 6> map; map.SetKeyValue("hi", "there"); - ASSERT_DEATH_CHECK(map.GetValueForKey(nullptr), "key"); + ASSERT_DEATH_CHECK(map.GetValueForKey(base::StringPiece(nullptr, 0)), "key"); EXPECT_STREQ("there", map.GetValueForKey("hi")); } From 7ed4d5c454c6702c900e31198cca3a18228b93e1 Mon Sep 17 00:00:00 2001 From: Nico Weber <thakis@chromium.org> Date: Fri, 7 Feb 2020 15:46:11 -0500 Subject: [PATCH 333/401] arm: Properly mark _ZN8crashpad14CaptureContextEP10ucontext_t as %function lld wants to remove bl/blx substitution for non-function symbols (https://reviews.llvm.org/D73542). GNU ld apparently already doesn't do it. Since _ZN8crashpad14CaptureContextEP10ucontext_t wasn't marked as a function, chromium's thumb code would then branch without mode transition into crashpads non-thumb assembly (in arm32). So mark the symbol as function, so that things work even if that patch relands. This should also make things work with GNU ld, though I haven't verified that it was broken before and works now. I also did this for aarch64 since it seems like The Right Thing To Do (assuming the assembler accepts it, which I also haven't checked -- the CQ will hopefully check that). Bug: chromium:1049649 Change-Id: I3452c16f0d52a2dc0397fd3d60d06b5c39a4b524 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2044144 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org> --- util/misc/capture_context_linux.S | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util/misc/capture_context_linux.S b/util/misc/capture_context_linux.S index de71e723..52215ee5 100644 --- a/util/misc/capture_context_linux.S +++ b/util/misc/capture_context_linux.S @@ -28,7 +28,11 @@ .globl CAPTURECONTEXT_SYMBOL2 #if defined(__i386__) || defined(__x86_64__) .balign 16, 0x90 -#elif defined(__arm__) || defined(__aarch64__) || defined(__mips__) +#elif defined(__arm__) || defined(__aarch64__) + .balign 4, 0x0 + .type CAPTURECONTEXT_SYMBOL, %function + .type CAPTURECONTEXT_SYMBOL2, %function +#elif defined(__mips__) .balign 4, 0x0 #endif From ff1036aa601703a3c55b8c3fce07295c5acedb9d Mon Sep 17 00:00:00 2001 From: Brian Sheedy <bsheedy@chromium.org> Date: Mon, 10 Feb 2020 11:48:51 -0800 Subject: [PATCH 334/401] Remove failing thread suspend DCHECK Removes a failing DCHECK in process_reader_win.cc caused by a race condition with a thread being injected into a process whose existing threads are already suspended. Bug: chromium:1007013 Change-Id: Ifa569220b28e8e2e5dfa6c32b2be4c57f61076b3 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2047803 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Brian Sheedy <bsheedy@chromium.org> --- snapshot/win/process_reader_win.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index 16280e96..51940c02 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -151,11 +151,17 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle, PLOG(ERROR) << "SuspendThread"; return false; } - DCHECK(previous_suspend_count > 0 || - suspension_state == ProcessSuspensionState::kRunning); - thread->suspend_count = - previous_suspend_count - - (suspension_state == ProcessSuspensionState::kSuspended ? 1 : 0); + if (previous_suspend_count <= 0 && + suspension_state == ProcessSuspensionState::kSuspended) { + LOG(WARNING) << "Thread " << thread->id + << " should be suspended, but previous_suspend_count is " + << previous_suspend_count; + thread->suspend_count = 0; + } else { + thread->suspend_count = + previous_suspend_count - + (suspension_state == ProcessSuspensionState::kSuspended ? 1 : 0); + } memset(&thread->context, 0, sizeof(thread->context)); #if defined(ARCH_CPU_32_BITS) From 5a8c228641341a53b8c0c875483a7286a0a9d998 Mon Sep 17 00:00:00 2001 From: Tao Bai <michaelbai@chromium.org> Date: Mon, 10 Feb 2020 15:11:53 -0800 Subject: [PATCH 335/401] Add document for base94_encoder - Also fix the command line issue Bug: crashpad:308 Change-Id: I2cace85f472acd049c1916b894c6ec36fe7fcc56 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2048267 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Tao Bai <michaelbai@chromium.org> --- tools/base94_encoder.cc | 2 +- tools/base94_encoder.md | 100 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 tools/base94_encoder.md diff --git a/tools/base94_encoder.cc b/tools/base94_encoder.cc index d4789250..1b184e9f 100644 --- a/tools/base94_encoder.cc +++ b/tools/base94_encoder.cc @@ -68,7 +68,7 @@ int Base94EncoderMain(int argc, char* argv[]) { bool encoding_valid = false; int opt; - while ((opt = getopt_long(argc, argv, "d:e", long_options, nullptr)) != -1) { + while ((opt = getopt_long(argc, argv, "de", long_options, nullptr)) != -1) { switch (opt) { case kOptionEncode: options.encoding = true; diff --git a/tools/base94_encoder.md b/tools/base94_encoder.md new file mode 100644 index 00000000..292c7a63 --- /dev/null +++ b/tools/base94_encoder.md @@ -0,0 +1,100 @@ +<!-- +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. +--> + +# base94_encoder(1) + +## Name + +base94_encoder—Encode/Decode the given file + +## Synopsis + +**base94_encoder** [_OPTION…_] input-file output-file + +## Description + +Encodes a file for printing safely by compressing and base94 encoding it. + +The base94_encoder can decode the input file by base94 decoding and +uncompressing it. + +## Options + + * **-e**, **--encode** + + Compress and encode the input file to a base94 encoded file. + + * **-d**, **--decode** + + Decode and decompress a base94 encoded file. + + * **--help** + + Display help and exit. + + * **--version** + + Output version information and exit. + +## Examples + +Encode file a to b: + +``` +$ base94_encoder --encode a b +``` + +Decode file b to a + +``` +$ base94_encoder --decode b a +``` + +## Exit Status + + * **0** + + Success. + + * **1** + + Failure, with a message printed to the standard error stream. + + +## Resources + +Crashpad home page: https://crashpad.chromium.org/. + +Report bugs at https://crashpad.chromium.org/bug/new. + +## Copyright + +Copyright 2020 [The Crashpad +Authors](https://chromium.googlesource.com/crashpad/crashpad/+/master/AUTHORS). + +## License + +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. From 07812f5bd61576340b8332ae25d5ec8832cd998a Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 18 Feb 2020 11:09:00 -0800 Subject: [PATCH 336/401] android: fix the gyp build Change-Id: Ic54fd61258f4ea5b3aaa83a252faa0053ca1f552 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2062773 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- handler/handler.gyp | 1 + util/util.gyp | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/handler/handler.gyp b/handler/handler.gyp index f80b5f02..f8313a53 100644 --- a/handler/handler.gyp +++ b/handler/handler.gyp @@ -28,6 +28,7 @@ '../minidump/minidump.gyp:crashpad_minidump', '../snapshot/snapshot.gyp:crashpad_snapshot', '../third_party/mini_chromium/mini_chromium.gyp:base', + '../third_party/zlib/zlib.gyp:zlib', '../tools/tools.gyp:crashpad_tool_support', '../util/util.gyp:crashpad_util', ], diff --git a/util/util.gyp b/util/util.gyp index 91c0310f..3c980e4e 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -26,6 +26,7 @@ '../third_party/zlib/zlib.gyp:zlib', '../third_party/lss/lss.gyp:lss', ], + 'defines': [ 'ZLIB_CONST' ], 'include_dirs': [ '..', '<(INTERMEDIATE_DIR)', @@ -49,6 +50,8 @@ 'file/filesystem_win.cc', 'file/file_writer.cc', 'file/file_writer.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', @@ -235,6 +238,17 @@ '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', 'string/split_string.cc', 'string/split_string.h', 'synchronization/semaphore_mac.cc', @@ -393,6 +407,13 @@ 'win/safe_terminate_process.asm', ], }], + ['OS=="android"', { + 'link_settings': { + 'libraries': [ + '-llog', + ], + }, + }], ['OS=="linux" or OS=="android"', { 'sources': [ 'net/http_transport_socket.cc', @@ -421,6 +442,11 @@ ['include', '^process/process_memory_linux\\.cc$'], ['include', '^process/process_memory_linux\\.h$'], ], + }, { # else: OS!="android" + 'sources!': [ + 'stream/log_output_stream.cc', + 'stream/log_output_stream.h', + ] }], ], }, From faed21a2862529b4ebead8cf178427b56fcacdca Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 18 Feb 2020 11:05:15 -0800 Subject: [PATCH 337/401] linux: Log register sizes on mismatch Bug:1051354 Change-Id: Ia7731a87420e61756b61d109f9c69970ec27c6cb Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2062776 Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/linux/ptracer.cc | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/util/linux/ptracer.cc b/util/linux/ptracer.cc index c6c92299..557e0d36 100644 --- a/util/linux/ptracer.cc +++ b/util/linux/ptracer.cc @@ -44,7 +44,8 @@ bool GetRegisterSet(pid_t tid, int set, Destination* dest, bool can_log) { return false; } if (iov.iov_len != sizeof(*dest)) { - LOG_IF(ERROR, can_log) << "Unexpected registers size"; + LOG_IF(ERROR, can_log) << "Unexpected registers size " << iov.iov_len + << " != " << sizeof(*dest); return false; } return true; @@ -176,7 +177,8 @@ bool GetFloatingPointRegisters32(pid_t tid, } } else { if (iov.iov_len != sizeof(context->f32.fpregs)) { - LOG_IF(ERROR, can_log) << "Unexpected registers size"; + LOG_IF(ERROR, can_log) << "Unexpected registers size " << iov.iov_len + << " != " << sizeof(context->f32.fpregs); return false; } context->f32.have_fpregs = true; @@ -197,7 +199,8 @@ bool GetFloatingPointRegisters32(pid_t tid, } } else { if (iov.iov_len != kArmVfpSize && iov.iov_len != sizeof(context->f32.vfp)) { - LOG_IF(ERROR, can_log) << "Unexpected registers size"; + LOG_IF(ERROR, can_log) << "Unexpected registers size " << iov.iov_len + << " != " << sizeof(context->f32.vfp); return false; } context->f32.have_vfp = true; @@ -223,7 +226,8 @@ bool GetFloatingPointRegisters64(pid_t tid, return false; } if (iov.iov_len != sizeof(context->f64)) { - LOG_IF(ERROR, can_log) << "Unexpected registers size"; + LOG_IF(ERROR, can_log) << "Unexpected registers size " << iov.iov_len + << " != " << sizeof(context->f64); return false; } return true; @@ -425,9 +429,10 @@ size_t GetGeneralPurposeRegistersAndLength(pid_t tid, bool GetGeneralPurposeRegisters32(pid_t tid, ThreadContext* context, bool can_log) { - if (GetGeneralPurposeRegistersAndLength(tid, context, can_log) != - sizeof(context->t32)) { - LOG_IF(ERROR, can_log) << "Unexpected registers size"; + size_t length = GetGeneralPurposeRegistersAndLength(tid, context, can_log); + if (length != sizeof(context->t32)) { + LOG_IF(ERROR, can_log) << "Unexpected registers size " << length + << " != " << sizeof(context->t32); return false; } return true; @@ -436,9 +441,10 @@ bool GetGeneralPurposeRegisters32(pid_t tid, bool GetGeneralPurposeRegisters64(pid_t tid, ThreadContext* context, bool can_log) { - if (GetGeneralPurposeRegistersAndLength(tid, context, can_log) != - sizeof(context->t64)) { - LOG_IF(ERROR, can_log) << "Unexpected registers size"; + size_t length = GetGeneralPurposeRegistersAndLength(tid, context, can_log); + if (length != sizeof(context->t64)) { + LOG_IF(ERROR, can_log) << "Unexpected registers size " << length + << " != " << sizeof(context->t64); return false; } return true; @@ -467,7 +473,9 @@ bool Ptracer::Initialize(pid_t pid) { } else if (length == sizeof(context.t32)) { is_64_bit_ = false; } else { - LOG_IF(ERROR, can_log_) << "Unexpected registers size"; + LOG_IF(ERROR, can_log_) + << "Unexpected registers size " << length + << " != " << sizeof(context.t64) << ", " << sizeof(context.t32); return false; } From 9ed82905471121a59fb8827627df3a98b7cdfe55 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Tue, 18 Feb 2020 14:49:10 -0500 Subject: [PATCH 338/401] Bring up skeleton crashpad_client_ios. First steps at bringing up the crashpad_client on iOS. Also updates the XCUITest to trigger various crashes, with some swizzling necessary to allow crashes. Change-Id: I87dd36bed1c052b509d14bfa29679ed81e58a377 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2039470 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Rohit Rao <rohitrao@chromium.org> --- client/BUILD.gn | 8 +- client/crashpad_client.h | 14 ++- client/crashpad_client_ios.cc | 75 +++++++++++ compat/BUILD.gn | 6 +- handler/BUILD.gn | 60 ++++----- test/ios/BUILD.gn | 1 + test/ios/crash_type_xctest.mm | 117 +++++++++++++++++- test/ios/host/BUILD.gn | 13 +- test/ios/host/application_delegate.mm | 35 +++++- ...o_placeholder.h => cptest_shared_object.h} | 24 +++- tools/BUILD.gn | 47 +++---- util/stdlib/strnlen.cc | 3 +- util/stdlib/strnlen.h | 4 +- 13 files changed, 327 insertions(+), 80 deletions(-) create mode 100644 client/crashpad_client_ios.cc rename test/ios/host/{edo_placeholder.h => cptest_shared_object.h} (54%) diff --git a/client/BUILD.gn b/client/BUILD.gn index a61c66d0..4ec03863 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -43,6 +43,10 @@ static_library("client") { ] } + if (crashpad_is_ios) { + sources += [ "crashpad_client_ios.cc" ] + } + if (crashpad_is_linux || crashpad_is_android) { set_sources_assignment_filter([]) sources += [ @@ -137,7 +141,9 @@ source_set("client_test") { "../util", ] - data_deps = [ "../handler:crashpad_handler" ] + if (!crashpad_is_ios) { + data_deps = [ "../handler:crashpad_handler" ] + } if (crashpad_is_win) { data_deps += [ "../handler:crashpad_handler_console" ] diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 207f9784..e0cd2f1f 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -423,9 +423,21 @@ class CrashpadClient { //! //! \param[in] unhandled_signals The set of unhandled signals void SetUnhandledSignals(const std::set<int>& unhandled_signals); - #endif // OS_LINUX || OS_ANDROID || DOXYGEN +#if defined(OS_IOS) || DOXYGEN + //! \brief Configures the process to direct its crashes to the iOS in-process + //! Crashpad handler. + //! + //! This method is only defined on iOS. + //! + //! \return `true` on success, `false` on failure with a message logged. + //! + //! TODO(justincohen): This method will need to take database, metrics_dir, + //! url and annotations eventually. + bool StartCrashpadInProcessHandler(); +#endif + #if defined(OS_MACOSX) || DOXYGEN //! \brief Sets the process’ crash handler to a Mach service registered with //! the bootstrap server. diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc new file mode 100644 index 00000000..c19152b8 --- /dev/null +++ b/client/crashpad_client_ios.cc @@ -0,0 +1,75 @@ +// 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 "client/crashpad_client.h" + +#include <unistd.h> + +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "client/client_argv_handling.h" +#include "util/posix/signals.h" + +namespace crashpad { + +namespace { + +// A base class for Crashpad signal handler implementations. +class SignalHandler { + public: + // Returns the currently installed signal hander. + static SignalHandler* Get() { + static SignalHandler* instance = new SignalHandler(); + return instance; + } + + bool Install(const std::set<int>* unhandled_signals) { + return Signals::InstallCrashHandlers( + HandleSignal, 0, &old_actions_, unhandled_signals); + } + + private: + SignalHandler() = default; + + // The base implementation for all signal handlers, suitable for calling + // directly to simulate signal delivery. + void HandleCrash(int signo, siginfo_t* siginfo, void* context) { + // Do Something. + + // Always call system handler. + Signals::RestoreHandlerAndReraiseSignalOnReturn( + siginfo, old_actions_.ActionForSignal(signo)); + } + + // The signal handler installed at OS-level. + static void HandleSignal(int signo, siginfo_t* siginfo, void* context) { + Get()->HandleCrash(signo, siginfo, context); + } + + Signals::OldActions old_actions_ = {}; + + DISALLOW_COPY_AND_ASSIGN(SignalHandler); +}; + +} // namespace + +CrashpadClient::CrashpadClient() {} + +CrashpadClient::~CrashpadClient() {} + +bool CrashpadClient::StartCrashpadInProcessHandler() { + return SignalHandler::Get()->Install(nullptr); +} + +} // namespace crashpad diff --git a/compat/BUILD.gn b/compat/BUILD.gn index 62ee5286..2f246565 100644 --- a/compat/BUILD.gn +++ b/compat/BUILD.gn @@ -19,7 +19,7 @@ config("compat_config") { if (crashpad_is_mac) { include_dirs += [ "mac" ] - } else { + } else if (!crashpad_is_ios) { include_dirs += [ "non_mac" ] } @@ -43,7 +43,7 @@ config("compat_config") { } template("compat_target") { - if (crashpad_is_mac) { + if (crashpad_is_mac || crashpad_is_ios) { # There are no sources to compile, which doesn’t mix will with a # static_library. group(target_name) { @@ -67,7 +67,7 @@ compat_target("compat") { "mac/mach/mach.h", "mac/sys/resource.h", ] - } else { + } else if (!crashpad_is_ios) { sources += [ "non_mac/mach-o/loader.h", "non_mac/mach/mach.h", diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 8862faba..3db3c899 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -140,25 +140,27 @@ source_set("handler_test") { } } -crashpad_executable("crashpad_handler") { - sources = [ "main.cc" ] +if (!crashpad_is_ios) { + crashpad_executable("crashpad_handler") { + sources = [ "main.cc" ] - deps = [ - ":handler", - "../build:default_exe_manifest_win", - "../compat", - "../third_party/mini_chromium:base", - ] + deps = [ + ":handler", + "../build:default_exe_manifest_win", + "../compat", + "../third_party/mini_chromium:base", + ] - if (crashpad_is_win) { - if (crashpad_is_in_chromium || crashpad_is_in_dart) { - remove_configs = [ "//build/config/win:console" ] - configs = [ "//build/config/win:windowed" ] - } else { - remove_configs = - [ "//third_party/mini_chromium/mini_chromium/build:win_console" ] - configs = - [ "//third_party/mini_chromium/mini_chromium/build:win_windowed" ] + if (crashpad_is_win) { + if (crashpad_is_in_chromium || crashpad_is_in_dart) { + remove_configs = [ "//build/config/win:console" ] + configs = [ "//build/config/win:windowed" ] + } else { + remove_configs = + [ "//third_party/mini_chromium/mini_chromium/build:win_console" ] + configs = + [ "//third_party/mini_chromium/mini_chromium/build:win_windowed" ] + } } } } @@ -190,19 +192,21 @@ if (crashpad_is_android) { } } -crashpad_executable("crashpad_handler_test_extended_handler") { - testonly = true +if (!crashpad_is_ios) { + crashpad_executable("crashpad_handler_test_extended_handler") { + testonly = true - sources = [ "crashpad_handler_test_extended_handler.cc" ] + sources = [ "crashpad_handler_test_extended_handler.cc" ] - deps = [ - ":handler", - "../build:default_exe_manifest_win", - "../compat", - "../minidump:test_support", - "../third_party/mini_chromium:base", - "../tools:tool_support", - ] + deps = [ + ":handler", + "../build:default_exe_manifest_win", + "../compat", + "../minidump:test_support", + "../third_party/mini_chromium:base", + "../tools:tool_support", + ] + } } if (crashpad_is_win) { diff --git a/test/ios/BUILD.gn b/test/ios/BUILD.gn index 225bf2a2..d548a279 100644 --- a/test/ios/BUILD.gn +++ b/test/ios/BUILD.gn @@ -40,6 +40,7 @@ source_set("google_test_runner") { deps = [ "../../build:ios_enable_arc", "../../build:ios_xctest", + "../../test/ios:google_test_runner_shared_headers", "../../third_party/mini_chromium:base", ] libs = [ "UIKit.framework" ] diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index ed72f613..8ebdafa4 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -14,26 +14,135 @@ #import <XCTest/XCTest.h> +#include <objc/runtime.h> #import "Service/Sources/EDOClientService.h" -#import "test/ios/host/edo_placeholder.h" +#import "test/ios/host/cptest_shared_object.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -@interface CPTestTestCase : XCTestCase +@interface CPTestTestCase : XCTestCase { + XCUIApplication* _app; +} + @end @implementation CPTestTestCase +- (void)handleCrashUnderSymbol:(id)arg1 { + // For now, do nothing. In the future this can be something testable. +} + ++ (void)setUp { + // Swizzle away the handleCrashUnderSymbol callback. Without this, any time + // the host app is intentionally crashed, the test is immediately failed. + SEL originalSelector = NSSelectorFromString(@"handleCrashUnderSymbol:"); + SEL swizzledSelector = @selector(handleCrashUnderSymbol:); + + Method originalMethod = class_getInstanceMethod( + objc_getClass("XCUIApplicationImpl"), originalSelector); + 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. + [EDOClientService setErrorHandler:^(NSError* error){ + // Do nothing. + }]; +} + - (void)setUp { - [[[XCUIApplication alloc] init] launch]; + _app = [[XCUIApplication alloc] init]; + [_app launch]; } - (void)testEDO { - EDOPlaceholder* rootObject = [EDOClientService rootObjectWithPort:12345]; + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; NSString* result = [rootObject testEDO]; XCTAssertEqualObjects(result, @"crashpad"); } +- (void)testSegv { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Crash the app. + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject crashSegv]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + +- (void)testKillAbort { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Crash the app. + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject crashKillAbort]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + +- (void)testTrap { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Crash the app. + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject crashTrap]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + +- (void)testAbort { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Crash the app. + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject crashAbort]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + +- (void)testBadAccess { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Crash the app. + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject crashBadAccess]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + @end diff --git a/test/ios/host/BUILD.gn b/test/ios/host/BUILD.gn index 39c8d999..e0d289d4 100644 --- a/test/ios/host/BUILD.gn +++ b/test/ios/host/BUILD.gn @@ -22,13 +22,9 @@ if (crashpad_is_in_chromium) { source_set("app_shared_sources") { testonly = true - sources = [ - "edo_placeholder.h", - ] + sources = [ "cptest_shared_object.h" ] configs += [ "../../..:crashpad_config" ] - deps = [ - "../../../build:ios_enable_arc", - ] + deps = [ "../../../build:ios_enable_arc" ] libs = [ "UIKit.framework" ] } @@ -45,6 +41,7 @@ static_library("app_host_sources") { deps = [ ":app_shared_sources", "../../../build:ios_enable_arc", + "../../../client", "../../../third_party/edo", ] libs = [ @@ -56,7 +53,5 @@ static_library("app_host_sources") { ios_app_bundle("ios_crash_xcuitests") { info_plist = "Info.plist" testonly = true - deps = [ - ":app_host_sources", - ] + deps = [ ":app_host_sources" ] } diff --git a/test/ios/host/application_delegate.mm b/test/ios/host/application_delegate.mm index 115d0ae5..a31d4d67 100644 --- a/test/ios/host/application_delegate.mm +++ b/test/ios/host/application_delegate.mm @@ -16,8 +16,9 @@ #import "Service/Sources/EDOHostNamingService.h" #import "Service/Sources/EDOHostService.h" +#include "client/crashpad_client.h" +#import "test/ios/host/cptest_shared_object.h" #import "test/ios/host/crash_view_controller.h" -#import "test/ios/host/edo_placeholder.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -28,6 +29,10 @@ - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + // Start up crashpad. + crashpad::CrashpadClient client; + client.StartCrashpadInProcessHandler(); + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; [self.window makeKeyAndVisible]; self.window.backgroundColor = UIColor.greenColor; @@ -37,17 +42,37 @@ // Start up EDO. [EDOHostService serviceWithPort:12345 - rootObject:[[EDOPlaceholder alloc] init] + rootObject:[[CPTestSharedObject alloc] init] queue:dispatch_get_main_queue()]; - [EDOHostNamingService.sharedService start]; - return YES; } @end -@implementation EDOPlaceholder +@implementation CPTestSharedObject - (NSString*)testEDO { return @"crashpad"; } + +- (void)crashBadAccess { + strcpy(0, "bla"); +} + +- (void)crashKillAbort { + kill(getpid(), SIGABRT); +} + +- (void)crashSegv { + long zero = 0; + *(long*)zero = 0xC045004d; +} + +- (void)crashTrap { + __builtin_trap(); +} + +- (void)crashAbort { + abort(); +} + @end diff --git a/test/ios/host/edo_placeholder.h b/test/ios/host/cptest_shared_object.h similarity index 54% rename from test/ios/host/edo_placeholder.h rename to test/ios/host/cptest_shared_object.h index 84bf0c44..483fce47 100644 --- a/test/ios/host/edo_placeholder.h +++ b/test/ios/host/cptest_shared_object.h @@ -12,13 +12,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CRASHPAD_TEST_IOS_HOST_EDO_PLACEHOLDER_H_ -#define CRASHPAD_TEST_IOS_HOST_EDO_PLACEHOLDER_H_ +#ifndef CRASHPAD_TEST_IOS_HOST_SHARED_OBJECT_H_ +#define CRASHPAD_TEST_IOS_HOST_SHARED_OBJECT_H_ #import <UIKit/UIKit.h> -@interface EDOPlaceholder : NSObject +@interface CPTestSharedObject : NSObject +// Returns the string "crashpad" for testing EDO. - (NSString*)testEDO; + +// Triggers an EXC_BAD_ACCESS exception and crash. +- (void)crashBadAccess; + +// 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; + +// Trigger a crash with an abort(). +- (void)crashAbort; @end -#endif // CRASHPAD_TEST_IOS_HOST_EDO_PLACEHOLDER_H_ +#endif // CRASHPAD_TEST_IOS_HOST_SHARED_OBJECT_H_ diff --git a/tools/BUILD.gn b/tools/BUILD.gn index 41f0fb69..5e0228b9 100644 --- a/tools/BUILD.gn +++ b/tools/BUILD.gn @@ -25,29 +25,31 @@ source_set("tool_support") { deps = [ "../third_party/mini_chromium:base" ] } -crashpad_executable("crashpad_database_util") { - sources = [ "crashpad_database_util.cc" ] +if (!crashpad_is_ios) { + crashpad_executable("crashpad_database_util") { + sources = [ "crashpad_database_util.cc" ] - deps = [ - ":tool_support", - "../build:default_exe_manifest_win", - "../client", - "../compat", - "../third_party/mini_chromium:base", - "../util", - ] -} + deps = [ + ":tool_support", + "../build:default_exe_manifest_win", + "../client", + "../compat", + "../third_party/mini_chromium:base", + "../util", + ] + } -crashpad_executable("crashpad_http_upload") { - sources = [ "crashpad_http_upload.cc" ] + crashpad_executable("crashpad_http_upload") { + sources = [ "crashpad_http_upload.cc" ] - deps = [ - ":tool_support", - "../build:default_exe_manifest_win", - "../compat", - "../third_party/mini_chromium:base", - "../util", - ] + deps = [ + ":tool_support", + "../build:default_exe_manifest_win", + "../compat", + "../third_party/mini_chromium:base", + "../util", + ] + } } crashpad_executable("base94_encoder") { @@ -60,7 +62,7 @@ crashpad_executable("base94_encoder") { ] } -if (!crashpad_is_fuchsia) { +if (!crashpad_is_fuchsia && !crashpad_is_ios) { crashpad_executable("generate_dump") { sources = [ "generate_dump.cc" ] @@ -88,7 +90,8 @@ if (!crashpad_is_fuchsia) { } if (crashpad_is_win) { - cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union + cflags = + [ "/wd4201" ] # nonstandard extension used : nameless struct/union } } } diff --git a/util/stdlib/strnlen.cc b/util/stdlib/strnlen.cc index a238728f..7ef8d3b1 100644 --- a/util/stdlib/strnlen.cc +++ b/util/stdlib/strnlen.cc @@ -14,7 +14,8 @@ #include "util/stdlib/strnlen.h" -#if defined(OS_MACOSX) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 +#if defined(OS_MACOSX) && !defined(OS_IOS) && \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_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 e85d8c7e..1db5f6e2 100644 --- a/util/stdlib/strnlen.h +++ b/util/stdlib/strnlen.h @@ -20,7 +20,7 @@ #include "build/build_config.h" -#if defined(OS_MACOSX) +#if defined(OS_MACOSX) && !defined(OS_IOS) #include <AvailabilityMacros.h> #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_MACOSX) || \ +#if !defined(OS_MACOSX) || defined(OS_IOS) || \ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7 inline size_t strnlen(const char* string, size_t max_length) { return ::strnlen(string, max_length); From 22701bb0e448dc7cf48a4de32457a6ae464d21bc Mon Sep 17 00:00:00 2001 From: Roland McGrath <mcgrathr@chromium.org> Date: Tue, 18 Feb 2020 18:18:23 -0800 Subject: [PATCH 339/401] fuchsia: Use zx_system_get_version_string The new API replaces zx_system_get_version and is simpler. Bug: fuchsia:45640 Change-Id: Ibc47703aba0e87e55265608b517e5953eada182f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2063908 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/fuchsia/system_snapshot_fuchsia.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/snapshot/fuchsia/system_snapshot_fuchsia.cc b/snapshot/fuchsia/system_snapshot_fuchsia.cc index d408dff4..c108529b 100644 --- a/snapshot/fuchsia/system_snapshot_fuchsia.cc +++ b/snapshot/fuchsia/system_snapshot_fuchsia.cc @@ -38,10 +38,7 @@ void SystemSnapshotFuchsia::Initialize(const timeval* snapshot_time) { // garnet/bin/uname/uname.c, however, this information isn't provided by // uname(). Additionally, uname() seems to hang if the network is in a bad // state when attempting to retrieve the nodename, so avoid it for now. - char kernel_version[256] = {}; - zx_status_t status = - zx_system_get_version(kernel_version, sizeof(kernel_version)); - ZX_LOG_IF(ERROR, status != ZX_OK, status) << "zx_system_get_version"; + std::string kernel_version = zx_system_get_version_string(); #if defined(ARCH_CPU_X86_64) static constexpr const char kArch[] = "x86_64"; @@ -50,8 +47,8 @@ void SystemSnapshotFuchsia::Initialize(const timeval* snapshot_time) { #else static constexpr const char kArch[] = "unknown"; #endif - os_version_full_ = - base::StringPrintf("Zircon prerelease %s %s", kernel_version, kArch); + os_version_full_ = base::StringPrintf( + "Zircon prerelease %s %s", kernel_version.c_str(), kArch); INITIALIZATION_STATE_SET_VALID(initialized_); } From f79cba47ba0d105be343f3e63d2f277cebf3a78c Mon Sep 17 00:00:00 2001 From: Yilong Li <liyl@google.com> Date: Thu, 20 Feb 2020 15:47:04 -0800 Subject: [PATCH 340/401] [lsan][crashpad] Suppress leak sanitizer on crashpad_test. Leak sanitizer detected bugs on the above tests. We suppress the leak sanitizer on the leaky targets for now, and these leaks need to be fixed to fully enable leak detector. Bug: fuchsia:46559 Change-Id: I0bd7a43cfefc0d4ac213651de6dceea4404c243b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2067412 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- BUILD.gn | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BUILD.gn b/BUILD.gn index 0ea3187b..2f39e5ae 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -35,6 +35,10 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "util:util_test", ] } + if (crashpad_is_in_fuchsia) { + # TODO(fuchsia:46559): Fix the leaks and remove this. + deps += [ "//build/config/sanitizers:suppress-lsan.DO-NOT-USE-THIS" ] + } } if (crashpad_is_in_fuchsia) { From 0c20aeabd37aa57f3fbbfa2b346169b5a6e46346 Mon Sep 17 00:00:00 2001 From: Leonard Chan <leonardchan@google.com> Date: Fri, 21 Feb 2020 11:33:02 -0800 Subject: [PATCH 341/401] [UBSan] Temporarily disable UBSan for snapshot and minidump UBSan was reporting reference binding to a misaligned address in Fuchsia. Disable UBSan for this target for now just to silence the runtime warnings, then come back and fix them. Bug: fuchsia:46805 Change-Id: Ic5d9b35161b6d998f1ff50eb8e978c44aff9b4ef Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2068051 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- BUILD.gn | 11 +++++++++++ minidump/BUILD.gn | 2 ++ snapshot/BUILD.gn | 2 ++ 3 files changed, 15 insertions(+) diff --git a/BUILD.gn b/BUILD.gn index 2f39e5ae..31c90918 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -20,6 +20,17 @@ 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", + ] +} + if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { test("crashpad_tests") { deps = [ diff --git a/minidump/BUILD.gn b/minidump/BUILD.gn index eb9f780d..35b19172 100644 --- a/minidump/BUILD.gn +++ b/minidump/BUILD.gn @@ -164,4 +164,6 @@ source_set("minidump_test") { if (crashpad_is_win) { cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union } + + configs += [ "..:disable_ubsan" ] } diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 150b8017..d3f51128 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -234,6 +234,8 @@ static_library("snapshot") { cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union libs = [ "powrprof.lib" ] } + + configs += [ "..:disable_ubsan" ] } if (crashpad_is_linux) { From d632f625a2f229ab5a7e0540d49deb3a75d91028 Mon Sep 17 00:00:00 2001 From: Nico Weber <thakis@chromium.org> Date: Sat, 22 Feb 2020 19:28:49 -0500 Subject: [PATCH 342/401] Fix a Wrange-loop-analysis warning in crashpad. Bug: chromium:1039697 Change-Id: I2c69b8a3ba9c070eef8ff5b8f0207311b020935f Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2069637 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org> --- tools/crashpad_database_util.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/crashpad_database_util.cc b/tools/crashpad_database_util.cc index 17a4771d..a0036163 100644 --- a/tools/crashpad_database_util.cc +++ b/tools/crashpad_database_util.cc @@ -561,7 +561,7 @@ int DatabaseUtilMain(int argc, char* argv[]) { } bool used_stdin = false; - for (const base::FilePath new_report_path : options.new_report_paths) { + for (const base::FilePath& new_report_path : options.new_report_paths) { std::unique_ptr<FileReaderInterface> file_reader; if (new_report_path.value() == FILE_PATH_LITERAL("-")) { From 8bad6f140e0bb3748f5e69cbccfdfe5266799e8b Mon Sep 17 00:00:00 2001 From: Leonard Chan <leonardchan@google.com> Date: Fri, 21 Feb 2020 20:40:08 -0800 Subject: [PATCH 343/401] [UBSan] Temporarily disable UBSan for gtest and file These should be the remaining instances of UB errors we see. Bug: fuchsia:46805 Change-Id: Id8285386fd6cb52518f6076ddb79ac60025f9f87 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2067754 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- BUILD.gn | 2 ++ third_party/gtest/BUILD.gn | 1 + util/BUILD.gn | 2 ++ 3 files changed, 5 insertions(+) diff --git a/BUILD.gn b/BUILD.gn index 31c90918..cba955dd 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -28,6 +28,8 @@ config("disable_ubsan") { visibility = [ "snapshot:snapshot", "minidump:minidump_test", + "third_party/gtest:gtest", + "util:util", ] } diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index 58197334..28137681 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -34,6 +34,7 @@ if (crashpad_is_in_chromium) { public_deps = [ "//third_party/googletest:gtest", ] + public_configs = [ "../..:disable_ubsan" ] } group("gmock") { testonly = true diff --git a/util/BUILD.gn b/util/BUILD.gn index f057fd96..aa890264 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -514,6 +514,8 @@ static_library("util") { if (crashpad_is_android || crashpad_is_linux) { deps += [ "../third_party/lss" ] } + + configs += [ "..:disable_ubsan" ] } if (!crashpad_is_android) { From 11b8eb10d4ad6ed50ee43d3bb50d13967d638dfa Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 2 Mar 2020 11:42:27 -0500 Subject: [PATCH 344/401] =?UTF-8?q?Don=E2=80=99t=20use=20the=20disappearin?= =?UTF-8?q?g=20MSVC=5FPUSH=5FDISABLE=5FWARNING()=20macro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: chromium:1053958 Change-Id: I4d3f6b5e1ea8f9433ce2db6da70f28cd4f539b7c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2081257 Reviewed-by: Nico Weber <thakis@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- minidump/minidump_extensions.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h index 67157449..9332f96e 100644 --- a/minidump/minidump_extensions.h +++ b/minidump/minidump_extensions.h @@ -25,14 +25,15 @@ #include "util/misc/pdb_structures.h" #include "util/misc/uuid.h" +#if defined(COMPILER_MSVC) // C4200 is "nonstandard extension used : zero-sized array in struct/union". // We would like to globally disable this warning, but unfortunately, the // compiler is buggy and only supports disabling it with a pragma, so we can't -// disable it with other silly warnings in build/common.gypi. See: +// disable it with other silly warnings in the build files. See: // https://connect.microsoft.com/VisualStudio/feedback/details/1114440 -MSVC_PUSH_DISABLE_WARNING(4200) +#pragma warning(push) +#pragma warning(disable: 4200) -#if defined(COMPILER_MSVC) #define PACKED #pragma pack(push, 1) #else @@ -498,11 +499,10 @@ struct ALIGNAS(4) PACKED MinidumpCrashpadInfo { #if defined(COMPILER_MSVC) #pragma pack(pop) +#pragma warning(pop) // C4200 #endif // COMPILER_MSVC #undef PACKED -MSVC_POP_WARNING() // C4200 - } // namespace crashpad #endif // CRASHPAD_MINIDUMP_MINIDUMP_EXTENSIONS_H_ From 3c573b54ae138c81c0224f22b38f5d439b56f9a1 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Mon, 2 Mar 2020 20:34:47 -0500 Subject: [PATCH 345/401] [ios] Fix iOS device build. Change-Id: Ib0f5af9680b4b626df2da006789eb846cd38579d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2081269 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- snapshot/BUILD.gn | 2 +- util/misc/capture_context.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index d3f51128..d3f69939 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -328,7 +328,7 @@ source_set("snapshot_test") { "sanitized/process_snapshot_sanitized_test.cc", "sanitized/sanitization_information_test.cc", ] - } else { + } else if (!crashpad_is_ios) { sources += [ "crashpad_info_client_options_test.cc" ] } diff --git a/util/misc/capture_context.h b/util/misc/capture_context.h index 541589df..a88a1033 100644 --- a/util/misc/capture_context.h +++ b/util/misc/capture_context.h @@ -17,7 +17,9 @@ #include "build/build_config.h" -#if defined(OS_MACOSX) +#if defined(OS_IOS) +#include <sys/ucontext.h> +#elif defined(OS_MACOSX) #include <mach/mach.h> #elif defined(OS_WIN) #include <windows.h> @@ -29,7 +31,9 @@ namespace crashpad { -#if defined(OS_MACOSX) +#if defined(OS_IOS) +using NativeCPUContext = ucontext_t; +#elif defined(OS_MACOSX) #if defined(ARCH_CPU_X86_FAMILY) using NativeCPUContext = x86_thread_state; #endif From 7500e2ef452a8902962bf89623d82e47ee023f07 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 3 Mar 2020 09:05:35 -0800 Subject: [PATCH 346/401] linux: add fallback-modes for memfd_create Bug: chromium:1051354 Change-Id: I5dbbb3b264c09060429db199aa9f046c2f317c48 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2080651 Reviewed-by: Mark Mentovai <mark@chromium.org> --- .../cros_crash_report_exception_handler.cc | 2 +- util/file/file_io.h | 19 +++++-- util/file/file_io_posix.cc | 57 +++++++++++++++---- util/file/file_io_test.cc | 17 ++++++ util/file/file_writer.cc | 2 +- util/file/file_writer.h | 2 +- 6 files changed, 81 insertions(+), 18 deletions(-) diff --git a/handler/linux/cros_crash_report_exception_handler.cc b/handler/linux/cros_crash_report_exception_handler.cc index b394d61f..92bc93e0 100644 --- a/handler/linux/cros_crash_report_exception_handler.cc +++ b/handler/linux/cros_crash_report_exception_handler.cc @@ -225,7 +225,7 @@ bool CrosCrashReportExceptionHandler::HandleExceptionWithConnection( AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump); FileWriter file_writer; - if (!file_writer.OpenMemfd(base::FilePath("/tmp/minidump"))) { + if (!file_writer.OpenMemfd(base::FilePath("minidump"))) { Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kOpenMemfdFailed); return false; } diff --git a/util/file/file_io.h b/util/file/file_io.h index 3c956cc2..6fa0f96d 100644 --- a/util/file/file_io.h +++ b/util/file/file_io.h @@ -399,16 +399,27 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, FilePermissions permissions); #if defined(OS_LINUX) -//! \brief Wraps memfd_create(), logging an error if the operation fails. -//! Unlike other file open operations, this doesn't set `O_CLOEXEC`. +//! \brief Opens an in-memory file for input and output. //! -//! \return The newly opened FileHandle, or an invalid FileHandle on failure. +//! This function first attempts to open the file with `memfd_create()`. If +//! `memfd_create()` isn't supported by the kernel, this function next attempts +//! to open a file using `O_TMPFILE`. If `O_TMPFILE` isn't supported, this +//! function finally falls back to creating a file with a randomized name in +//! `/tmp` and immediately `unlink()`ing it. +//! +//! Unlike other file open operations, this function doesn't set `O_CLOEXEC`. +//! +//! \param name A name associated with the file. This name does not indicate any +//! exact path and may not be used at all, depending on the strategy used to +//! create the file. The name should not contain any '/' characters. +//! \return The newly opened FileHandle, or an invalid FileHandle on failure, +//! with a message logged. //! //! \sa ScopedFileHandle //! \sa LoggingOpenFileForRead //! \sa LoggingOpenFileForWrite //! \sa LoggingOpenFileForReadAndWrite -FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path); +FileHandle LoggingOpenMemoryFileForReadAndWrite(const base::FilePath& name); #endif // OS_LINUX //! \brief Wraps OpenFileForReadAndWrite(), logging an error if the operation diff --git a/util/file/file_io_posix.cc b/util/file/file_io_posix.cc index b72a48eb..91b252a0 100644 --- a/util/file/file_io_posix.cc +++ b/util/file/file_io_posix.cc @@ -14,6 +14,7 @@ #include "util/file/file_io.h" +#include <errno.h> #include <fcntl.h> #include <sys/file.h> #include <sys/mman.h> @@ -26,7 +27,9 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/posix/eintr_wrapper.h" +#include "base/strings/stringprintf.h" #include "build/build_config.h" +#include "util/misc/random_string.h" namespace crashpad { @@ -98,13 +101,6 @@ FileHandle OpenFileForOutput(int rdwr_or_wronly, flags, permissions == FilePermissions::kWorldReadable ? 0644 : 0600)); } - -#if defined(OS_LINUX) -FileHandle OpenMemFileForOutput(const base::FilePath& path) { - return HANDLE_EINTR(memfd_create(path.value().c_str(), 0)); -} -#endif - } // namespace namespace internal { @@ -157,10 +153,49 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path, } #if defined(OS_LINUX) -FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path) { - FileHandle fd = OpenMemFileForOutput(path); - PLOG_IF(ERROR, fd < 0) << "memfd_create " << path.value(); - return fd; +FileHandle LoggingOpenMemoryFileForReadAndWrite(const base::FilePath& name) { + DCHECK(name.value().find('/') == std::string::npos); + + int result = HANDLE_EINTR(memfd_create(name.value().c_str(), 0)); + if (result >= 0 || errno != ENOSYS) { + PLOG_IF(ERROR, result < 0) << "memfd_create"; + return result; + } + + const char* tmp = getenv("TMPDIR"); + tmp = tmp ? tmp : "/tmp"; + + result = HANDLE_EINTR(open(tmp, O_RDWR | O_EXCL | O_TMPFILE, 0600)); + if (result >= 0 || + // These are the expected possible error codes indicating that O_TMPFILE + // doesn't have kernel or filesystem support. O_TMPFILE was added in Linux + // 3.11. Experimentation confirms that at least Linux 2.6.29 and Linux + // 3.10 set errno to EISDIR. EOPNOTSUPP is returned when the filesystem + // doesn't support O_TMPFILE. The man pages also mention ENOENT as an + // error code to check, but the language implies it would only occur when + // |tmp| is also an invalid directory. EINVAL is mentioned as a possible + // error code for any invalid values in flags, but O_TMPFILE isn't + // mentioned explicitly in this context and hasn't been observed in + // practice. + (errno != EISDIR && errno != EOPNOTSUPP)) { + PLOG_IF(ERROR, result < 0) << "open"; + return result; + } + + std::string path = base::StringPrintf("%s/%s.%d.%s", + tmp, + name.value().c_str(), + getpid(), + RandomString().c_str()); + result = HANDLE_EINTR(open(path.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)); + if (result < 0) { + PLOG(ERROR) << "open"; + return result; + } + if (unlink(path.c_str()) != 0) { + PLOG(WARNING) << "unlink"; + } + return result; } #endif diff --git a/util/file/file_io_test.cc b/util/file/file_io_test.cc index 0fdd25c4..0efded8a 100644 --- a/util/file/file_io_test.cc +++ b/util/file/file_io_test.cc @@ -473,6 +473,23 @@ TEST(FileIO, LoggingOpenFileForReadAndWrite) { TestOpenFileForWrite(LoggingOpenFileForReadAndWrite); } +#if defined(OS_LINUX) +TEST(FileIO, LoggingOpenMemoryFileForReadAndWrite) { + ScopedFileHandle handle( + LoggingOpenMemoryFileForReadAndWrite(base::FilePath("memfile"))); + ASSERT_TRUE(handle.is_valid()); + + static constexpr char kTestData[] = "somedata"; + ASSERT_TRUE(LoggingWriteFile(handle.get(), kTestData, sizeof(kTestData))); + + ASSERT_EQ(LoggingSeekFile(handle.get(), 0, SEEK_SET), 0); + + char buffer[sizeof(kTestData)]; + ASSERT_TRUE(LoggingReadFileExactly(handle.get(), buffer, sizeof(buffer))); + EXPECT_EQ(memcmp(buffer, kTestData, sizeof(buffer)), 0); +} +#endif // OS_LINUX + enum class ReadOrWrite : bool { kRead, kWrite, diff --git a/util/file/file_writer.cc b/util/file/file_writer.cc index de28575d..6dff975a 100644 --- a/util/file/file_writer.cc +++ b/util/file/file_writer.cc @@ -174,7 +174,7 @@ bool FileWriter::Open(const base::FilePath& path, #if defined(OS_LINUX) bool FileWriter::OpenMemfd(const base::FilePath& path) { CHECK(!file_.is_valid()); - file_.reset(LoggingOpenMemFileForWrite(path)); + file_.reset(LoggingOpenMemoryFileForReadAndWrite(path)); if (!file_.is_valid()) { return false; } diff --git a/util/file/file_writer.h b/util/file/file_writer.h index 663adff1..4b99b375 100644 --- a/util/file/file_writer.h +++ b/util/file/file_writer.h @@ -132,7 +132,7 @@ class FileWriter : public FileWriterInterface { FilePermissions permissions); #if defined(OS_LINUX) - //! \brief Wraps LoggingOpenMemFileForWrite(). + //! \brief Wraps LoggingOpenMemoryFileForWrite(). //! //! \return `true` if the operation succeeded, `false` if it failed, with an //! error message logged. From e1b3bd11cd088d70c945ddda76937b220b0082ad Mon Sep 17 00:00:00 2001 From: Jinke Fan <fanjinke51@yeah.net> Date: Mon, 3 Jun 2019 16:44:04 +0800 Subject: [PATCH 347/401] Add support for Hygon Dhyana CPU This patch is used to add support Hygon Dhyana x86 vendor id (HygonGenuine). More details can be found on: http://lkml.kernel.org/r/5ce86123a7b9dad925ac583d88d2f921040e859b.1538583282.git.puwen@hygon.cn Change-Id: I53445a8a63421811401b6a6a40e664d2600a3ec8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1640959 Reviewed-by: Mark Mentovai <mark@chromium.org> --- compat/non_win/dbghelp.h | 2 +- minidump/minidump_system_info_writer.cc | 2 +- snapshot/linux/system_snapshot_linux_test.cc | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compat/non_win/dbghelp.h b/compat/non_win/dbghelp.h index 5ce88b88..ded912e7 100644 --- a/compat/non_win/dbghelp.h +++ b/compat/non_win/dbghelp.h @@ -214,7 +214,7 @@ union __attribute__((packed, aligned(4))) CPU_INFORMATION { //! `cpuid 0x80000001` `edx`. //! //! This field is only valid if #VendorId identifies the CPU vendor as - //! “AuthenticAMD”. + //! “AuthenticAMD” or "HygonGenuine". uint32_t AMDExtendedCpuFeatures; } X86CpuInfo; diff --git a/minidump/minidump_system_info_writer.cc b/minidump/minidump_system_info_writer.cc index 9bc013dc..06aeecda 100644 --- a/minidump/minidump_system_info_writer.cc +++ b/minidump/minidump_system_info_writer.cc @@ -151,7 +151,7 @@ void MinidumpSystemInfoWriter::InitializeFromSnapshot( SetCPUX86VersionAndFeatures(system_snapshot->CPUX86Signature(), system_snapshot->CPUX86Features() & 0xffffffff); - if (cpu_vendor == "AuthenticAMD") { + if (cpu_vendor == "AuthenticAMD" || cpu_vendor == "HygonGenuine") { SetCPUX86AMDExtendedFeatures( system_snapshot->CPUX86ExtendedFeatures() & 0xffffffff); } diff --git a/snapshot/linux/system_snapshot_linux_test.cc b/snapshot/linux/system_snapshot_linux_test.cc index 46d3845f..f3013b54 100644 --- a/snapshot/linux/system_snapshot_linux_test.cc +++ b/snapshot/linux/system_snapshot_linux_test.cc @@ -77,7 +77,8 @@ TEST(SystemSnapshotLinux, Basic) { EXPECT_PRED1( [](std::string vendor) { - return vendor == "GenuineIntel" || vendor == "AuthenticAMD"; + return vendor == "GenuineIntel" || vendor == "AuthenticAMD" || + vendor == "HygonGenuine"; }, system.CPUVendor()); From 42da41d24a21acf469e7a3a1759f551733fb403c Mon Sep 17 00:00:00 2001 From: Rohit Rao <rohitrao@chromium.org> Date: Tue, 3 Mar 2020 14:24:38 -0500 Subject: [PATCH 348/401] Targets iPhone 8 when running tests. The iPhone 8 simulator should be available in both Xcode 10.2 and Xcode 11.3. BUG=None Change-Id: I26570eb2406f67b3663ac9ecb7e7440c0f9fa70d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2085353 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Rohit Rao <rohitrao@chromium.org> --- build/run_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/run_tests.py b/build/run_tests.py index 44620fb8..38473cd0 100755 --- a/build/run_tests.py +++ b/build/run_tests.py @@ -437,7 +437,7 @@ def _RunOnFuchsiaTarget(binary_dir, test, device_name, extra_command_line): def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False): - """Runs the given iOS |test| app on iPhone X with the default OS version.""" + """Runs the given iOS |test| app on iPhone 8 with the default OS version.""" def xctest(binary_dir, test): """Returns a dict containing the xctestrun data needed to run an @@ -496,7 +496,7 @@ def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False): subprocess.check_call(['xcodebuild', 'test-without-building', '-xctestrun', xctestrun_path, '-destination', - 'platform=iOS Simulator,name=iPhone X']) + 'platform=iOS Simulator,name=iPhone 8']) # This script is primarily used from the waterfall so that the list of tests # that are run is maintained in-tree, rather than in a separate infrastructure From 209124197145da8e1b114439cf8653f3b0b2033f Mon Sep 17 00:00:00 2001 From: Martin Vejdarski <martin@mainframe.co.uk> Date: Thu, 5 Mar 2020 10:57:12 +0700 Subject: [PATCH 349/401] Roll crashpad/third_party/mini_chromium/mini_chromium/ f8f1182ad..c426ff98e (3 commits) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://chromium.googlesource.com/chromium/mini_chromium/+log/f8f1182adb80..c426ff98e1d9 $ git log f8f1182ad..c426ff98e --date=short --no-merges --format='%ad %ae %s' 2020-03-05 martin fix build issue with objc flags 2020-03-05 martin add extra flags to gn 2020-03-02 mark Don’t use the disappearing MSVC_PUSH_DISABLE_WARNING() macro Created with: roll-dep crashpad/third_party/mini_chromium/mini_chromium Change-Id: I5d49cfe778e31c47b9e153107dc79abe2a726070 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2087554 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 21dc3f0f..f7355b78 100644 --- a/DEPS +++ b/DEPS @@ -42,7 +42,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'f8f1182adb804675b2aa4fb3ce03f6f884fae474', + 'c426ff98e1d9e9d59777fe8b883a5c0ceeca9ca3', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From b109e4ce389775651eb2cdb3cc1ffb95ab808d3b Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Wed, 4 Mar 2020 15:19:46 -0500 Subject: [PATCH 350/401] [ios] Bring up first draft process and module snapshot. Gather most of the necessary information for the module snapshot. Note that: - The 'capture' portion of this CL will be moved out of the snapshot interface and into a separate in-process dump to disk location. - All of the pointer dereferences need to be wrapped in vm_read. - The read-fast-and-dump logic in module_snapshot may end up in a different file completely, but until we pick a serialization/deserialization method, keep it in module_snapshot_ios. Change-Id: Ie80c739c167634520d13ec920a29a80116aa3bfe Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2079196 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- BUILD.gn | 13 +- client/BUILD.gn | 16 ++ client/crashpad_client.h | 7 + client/crashpad_client_ios.cc | 22 ++- client/crashpad_client_ios_test.cc | 32 ++++ snapshot/BUILD.gn | 13 ++ snapshot/ios/module_snapshot_ios.cc | 237 +++++++++++++++++++++++++++ snapshot/ios/module_snapshot_ios.h | 112 +++++++++++++ snapshot/ios/process_snapshot_ios.cc | 162 ++++++++++++++++++ snapshot/ios/process_snapshot_ios.h | 75 +++++++++ 10 files changed, 676 insertions(+), 13 deletions(-) create mode 100644 client/crashpad_client_ios_test.cc create mode 100644 snapshot/ios/module_snapshot_ios.cc create mode 100644 snapshot/ios/module_snapshot_ios.h create mode 100644 snapshot/ios/process_snapshot_ios.cc create mode 100644 snapshot/ios/process_snapshot_ios.h diff --git a/BUILD.gn b/BUILD.gn index cba955dd..3d0dc265 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -36,12 +36,12 @@ config("disable_ubsan") { if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { test("crashpad_tests") { deps = [ + "client:client_test", "test:gmock_main", "test:test_test", ] if (!crashpad_is_ios) { deps += [ - "client:client_test", "handler:handler_test", "minidump:minidump_test", "snapshot:snapshot_test", @@ -138,9 +138,7 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { } package("crashpad_database_util") { - deps = [ - "tools:crashpad_database_util", - ] + deps = [ "tools:crashpad_database_util" ] binaries = [ { @@ -156,9 +154,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "client:client_test", "test:gmock_main", ] - if (crashpad_is_ios) { - deps -= [ "client:client_test" ] - } } test("crashpad_handler_test") { @@ -212,8 +207,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { if (crashpad_is_ios) { group("ios_xcuitests") { testonly = true - deps = [ - "test/ios:all_tests", - ] + deps = [ "test/ios:all_tests" ] } } diff --git a/client/BUILD.gn b/client/BUILD.gn index 4ec03863..476ceb2c 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -93,6 +93,11 @@ static_library("client") { cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union } + # TODO(justincohen): Temporary dependency to bring up the iOS client. + if (crashpad_is_ios) { + deps += [ "../snapshot" ] + } + if (crashpad_is_linux || crashpad_is_android) { deps += [ "../third_party/lss" ] } @@ -126,6 +131,17 @@ source_set("client_test") { sources += [ "crashpad_client_win_test.cc" ] } + if (crashpad_is_ios) { + sources += [ "crashpad_client_ios_test.cc" ] + sources -= [ + "annotation_list_test.cc", + "annotation_test.cc", + "crash_report_database_test.cc", + "prune_crash_reports_test.cc", + "settings_test.cc", + ] + } + if (crashpad_is_linux || crashpad_is_android) { sources += [ "crashpad_client_linux_test.cc" ] } diff --git a/client/crashpad_client.h b/client/crashpad_client.h index e0cd2f1f..7a6a18a9 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -436,6 +436,13 @@ class CrashpadClient { //! TODO(justincohen): This method will need to take database, metrics_dir, //! url and annotations eventually. bool StartCrashpadInProcessHandler(); + + // TODO(justincohen): This method is purely for bringing up iOS interfaces. + //! \brief Requests that the handler capture a dump even though there hasn't + //! been a crash. + //! + //! A handler must have already been installed before calling this method. + static void DumpWithoutCrash(); #endif #if defined(OS_MACOSX) || DOXYGEN diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index c19152b8..8e3fafaa 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -19,6 +19,7 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" #include "client/client_argv_handling.h" +#include "snapshot/ios/process_snapshot_ios.h" #include "util/posix/signals.h" namespace crashpad { @@ -39,13 +40,21 @@ class SignalHandler { HandleSignal, 0, &old_actions_, unhandled_signals); } + void HandleCrash(int signo, siginfo_t* siginfo, void* context) { + // TODO(justincohen): This is incomplete. + ProcessSnapshotIOS process_snapshot; + process_snapshot.Initialize(); + } + private: SignalHandler() = default; // The base implementation for all signal handlers, suitable for calling // directly to simulate signal delivery. - void HandleCrash(int signo, siginfo_t* siginfo, void* context) { - // Do Something. + void HandleCrashAndReraiseSignal(int signo, + siginfo_t* siginfo, + void* context) { + HandleCrash(signo, siginfo, context); // Always call system handler. Signals::RestoreHandlerAndReraiseSignalOnReturn( @@ -54,7 +63,7 @@ class SignalHandler { // The signal handler installed at OS-level. static void HandleSignal(int signo, siginfo_t* siginfo, void* context) { - Get()->HandleCrash(signo, siginfo, context); + Get()->HandleCrashAndReraiseSignal(signo, siginfo, context); } Signals::OldActions old_actions_ = {}; @@ -72,4 +81,11 @@ bool CrashpadClient::StartCrashpadInProcessHandler() { return SignalHandler::Get()->Install(nullptr); } +// static +void CrashpadClient::DumpWithoutCrash() { + DCHECK(SignalHandler::Get()); + + siginfo_t siginfo = {}; + SignalHandler::Get()->HandleCrash(siginfo.si_signo, &siginfo, nullptr); +} } // namespace crashpad diff --git a/client/crashpad_client_ios_test.cc b/client/crashpad_client_ios_test.cc new file mode 100644 index 00000000..6ed45794 --- /dev/null +++ b/client/crashpad_client_ios_test.cc @@ -0,0 +1,32 @@ +// 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 "client/crashpad_client.h" + +#include "gtest/gtest.h" + +namespace crashpad { +namespace test { +namespace { + +// TODO(justincohen): This is a placeholder. +TEST(CrashpadIOSClient, DumpWithoutCrash) { + crashpad::CrashpadClient client; + client.StartCrashpadInProcessHandler(); + client.DumpWithoutCrash(); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index d3f69939..bfee6f51 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -108,6 +108,15 @@ static_library("snapshot") { ] } + if (crashpad_is_ios) { + sources += [ + "ios/module_snapshot_ios.cc", + "ios/module_snapshot_ios.h", + "ios/process_snapshot_ios.cc", + "ios/process_snapshot_ios.h", + ] + } + if (crashpad_is_linux || crashpad_is_android) { set_sources_assignment_filter([]) sources += [ @@ -230,6 +239,10 @@ static_library("snapshot") { "../util", ] + if (crashpad_is_ios) { + deps -= [ "../client" ] + } + if (crashpad_is_win) { cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union libs = [ "powrprof.lib" ] diff --git a/snapshot/ios/module_snapshot_ios.cc b/snapshot/ios/module_snapshot_ios.cc new file mode 100644 index 00000000..824ad8a5 --- /dev/null +++ b/snapshot/ios/module_snapshot_ios.cc @@ -0,0 +1,237 @@ +// 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/ios/module_snapshot_ios.h" + +#include <mach-o/loader.h> +#include <mach/mach.h> + +#include "base/files/file_path.h" +#include "base/mac/mach_logging.h" +#include "util/misc/from_pointer_cast.h" +#include "util/misc/uuid.h" + +namespace crashpad { +namespace internal { + +ModuleSnapshotIOS::ModuleSnapshotIOS() + : ModuleSnapshot(), + name_(), + address_(0), + size_(0), + timestamp_(0), + dylib_version_(0), + source_version_(0), + filetype_(0), + initialized_() {} + +ModuleSnapshotIOS::~ModuleSnapshotIOS() {} + +// static. +const dyld_all_image_infos* ModuleSnapshotIOS::DyldAllImageInfo() { + task_dyld_info_data_t dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + + kern_return_t kr = task_info(mach_task_self(), + TASK_DYLD_INFO, + reinterpret_cast<task_info_t>(&dyld_info), + &count); + if (kr != KERN_SUCCESS) { + MACH_LOG(WARNING, kr) << "task_info"; + return 0; + } + + return reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr); +} + +bool ModuleSnapshotIOS::InitializeDyld(const dyld_all_image_infos* images) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + name_ = images->dyldPath; + address_ = FromPointerCast<uint64_t>(images->dyldImageLoadAddress); + return FinishInitialization(); +} + +bool ModuleSnapshotIOS::Initialize(const dyld_image_info* image) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + name_ = image->imageFilePath; + address_ = FromPointerCast<uint64_t>(image->imageLoadAddress); + timestamp_ = image->imageFileModDate; + return FinishInitialization(); +} + +bool ModuleSnapshotIOS::FinishInitialization() { +#ifndef ARCH_CPU_64_BITS +#error Only 64-bit Mach-O is supported +#endif + DCHECK(address_); + const mach_header_64* header = + reinterpret_cast<const mach_header_64*>(address_); + const load_command* command = + reinterpret_cast<const load_command*>(header + 1); + // Make sure that the basic load command structure doesn’t overflow the + // space allotted for load commands, as well as iterating through ncmds. + 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) { + segment_command_64* segment = + reinterpret_cast<segment_command_64*>(&command); + if (strcmp(segment->segname, SEG_TEXT) == 0) { + size_ = segment->vmsize; + } + } else if (command->cmd == LC_ID_DYLIB) { + dylib_command* dylib = reinterpret_cast<dylib_command*>(&command); + dylib_version_ = dylib->dylib.current_version; + } else if (command->cmd == LC_SOURCE_VERSION) { + source_version_command* source_version = + reinterpret_cast<source_version_command*>(&command); + source_version_ = source_version->version; + } else if (command->cmd == LC_UUID) { + uuid_command* uuid = reinterpret_cast<uuid_command*>(&command); + uuid_.InitializeFromBytes(uuid->uuid); + } + + command = reinterpret_cast<const load_command*>( + reinterpret_cast<const uint8_t*>(command + command->cmdsize)); + + // TODO(justincohen): Warn-able things: + // - Bad Mach-O magic (and give up trying to process the module) + // - Unrecognized Mach-O type + // - No SEG_TEXT + // - More than one SEG_TEXT + // - More than one LC_ID_DYLIB, LC_SOURCE_VERSION, or LC_UUID + // - No LC_ID_DYLIB in a dylib file + // - LC_ID_DYLIB in a non-dylib file + // And more optional: + // - Missing LC_UUID (although it leaves us with a big "?") + // - Missing LC_SOURCE_VERSION. + } + + filetype_ = header->filetype; + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +std::string ModuleSnapshotIOS::Name() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return name_; +} + +uint64_t ModuleSnapshotIOS::Address() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return address_; +} + +uint64_t ModuleSnapshotIOS::Size() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return size_; +} + +time_t ModuleSnapshotIOS::Timestamp() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return timestamp_; +} + +void ModuleSnapshotIOS::FileVersion(uint16_t* version_0, + uint16_t* version_1, + uint16_t* version_2, + uint16_t* version_3) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + if (filetype_ == MH_DYLIB) { + *version_0 = (dylib_version_ & 0xffff0000) >> 16; + *version_1 = (dylib_version_ & 0x0000ff00) >> 8; + *version_2 = (dylib_version_ & 0x000000ff); + *version_3 = 0; + } else { + *version_0 = 0; + *version_1 = 0; + *version_2 = 0; + *version_3 = 0; + } +} + +void ModuleSnapshotIOS::SourceVersion(uint16_t* version_0, + uint16_t* version_1, + uint16_t* version_2, + uint16_t* version_3) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *version_0 = (source_version_ & 0xffff000000000000u) >> 48; + *version_1 = (source_version_ & 0x0000ffff00000000u) >> 32; + *version_2 = (source_version_ & 0x00000000ffff0000u) >> 16; + *version_3 = source_version_ & 0x000000000000ffffu; +} + +ModuleSnapshot::ModuleType ModuleSnapshotIOS::GetModuleType() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + switch (filetype_) { + case MH_EXECUTE: + return kModuleTypeExecutable; + case MH_DYLIB: + return kModuleTypeSharedLibrary; + case MH_DYLINKER: + return kModuleTypeDynamicLoader; + case MH_BUNDLE: + return kModuleTypeLoadableModule; + default: + return kModuleTypeUnknown; + } +} + +void ModuleSnapshotIOS::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *uuid = uuid_; + *age = 0; +} + +std::string ModuleSnapshotIOS::DebugFileName() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return base::FilePath(Name()).BaseName().value(); +} + +std::vector<uint8_t> ModuleSnapshotIOS::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<uint8_t>(); +} + +std::vector<std::string> ModuleSnapshotIOS::AnnotationsVector() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<std::string>(); +} + +std::map<std::string, std::string> ModuleSnapshotIOS::AnnotationsSimpleMap() + const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::map<std::string, std::string>(); +} + +std::vector<AnnotationSnapshot> ModuleSnapshotIOS::AnnotationObjects() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<AnnotationSnapshot>(); +} + +std::set<CheckedRange<uint64_t>> ModuleSnapshotIOS::ExtraMemoryRanges() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::set<CheckedRange<uint64_t>>(); +} + +std::vector<const UserMinidumpStream*> +ModuleSnapshotIOS::CustomMinidumpStreams() const { + return std::vector<const UserMinidumpStream*>(); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/ios/module_snapshot_ios.h b/snapshot/ios/module_snapshot_ios.h new file mode 100644 index 00000000..7d0bbdc8 --- /dev/null +++ b/snapshot/ios/module_snapshot_ios.h @@ -0,0 +1,112 @@ +// 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_IOS_MODULE_SNAPSHOT_IOS_H_ +#define CRASHPAD_SNAPSHOT_IOS_MODULE_SNAPSHOT_IOS_H_ + +#include <mach-o/dyld_images.h> +#include <stdint.h> +#include <sys/types.h> + +#include <map> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "client/crashpad_info.h" +#include "snapshot/crashpad_info_client_options.h" +#include "snapshot/module_snapshot.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { + +//! \brief A ModuleSnapshot of a code module (binary image) loaded into a +//! running (or crashed) process on an iOS system. +class ModuleSnapshotIOS final : public ModuleSnapshot { + public: + ModuleSnapshotIOS(); + ~ModuleSnapshotIOS() override; + + // TODO(justincohen): This function is temporary, and will be broken into two + // parts. One to do an in-process dump of all the relevant information, and + // two to initialize the snapshot after the in-process dump is loaded. + //! \brief Initializes the object. + //! + //! \param[in] image The mach-o image to be loaded. + //! + //! \return `true` if the snapshot could be created. + bool Initialize(const dyld_image_info* image); + + // TODO(justincohen): This function is temporary, and will be broken into two + // parts. One to do an in-process dump of all the relevant information, and + // two to initialize the snapshot after the in-process dump is loaded. + //! \brief Initializes the object specifically for the dyld module. + //! + //! \param[in] images The structure containing the necessary dyld information. + //! + //! \return `true` if the snapshot could be created. + bool InitializeDyld(const dyld_all_image_infos* images); + + //! \brief Returns options from the module’s CrashpadInfo structure. + //! + //! \param[out] options Options set in the module’s CrashpadInfo structure. + void GetCrashpadOptions(CrashpadInfoClientOptions* options); + + static const dyld_all_image_infos* DyldAllImageInfo(); + + // ModuleSnapshot: + std::string Name() const override; + uint64_t Address() const override; + uint64_t Size() const override; + time_t Timestamp() const override; + void FileVersion(uint16_t* version_0, + uint16_t* version_1, + uint16_t* version_2, + uint16_t* version_3) const override; + void SourceVersion(uint16_t* version_0, + uint16_t* version_1, + uint16_t* version_2, + uint16_t* version_3) const override; + ModuleType GetModuleType() const override; + void UUIDAndAge(UUID* uuid, uint32_t* age) const override; + std::string DebugFileName() const override; + std::vector<uint8_t> BuildID() const override; + std::vector<std::string> AnnotationsVector() const override; + std::map<std::string, std::string> AnnotationsSimpleMap() const override; + std::vector<AnnotationSnapshot> AnnotationObjects() const override; + std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const override; + std::vector<const UserMinidumpStream*> CustomMinidumpStreams() const override; + + private: + // Gather the the module information based off of a mach_header_64 |address_|. + bool FinishInitialization(); + + std::string name_; + uint64_t address_; + uint64_t size_; + time_t timestamp_; + uint32_t dylib_version_; + uint64_t source_version_; + uint32_t filetype_; + UUID uuid_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ModuleSnapshotIOS); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_IOS_MODULE_SNAPSHOT_IOS_H_ diff --git a/snapshot/ios/process_snapshot_ios.cc b/snapshot/ios/process_snapshot_ios.cc new file mode 100644 index 00000000..666fc198 --- /dev/null +++ b/snapshot/ios/process_snapshot_ios.cc @@ -0,0 +1,162 @@ +// 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/ios/process_snapshot_ios.h" + +#include <mach-o/loader.h> +#include <mach/mach.h> + +#include <utility> + +#include "base/logging.h" +#include "base/mac/mach_logging.h" + +namespace crashpad { + +ProcessSnapshotIOS::ProcessSnapshotIOS() + : ProcessSnapshot(), + modules_(), + report_id_(), + client_id_(), + annotations_simple_map_(), + snapshot_time_(), + initialized_() {} + +ProcessSnapshotIOS::~ProcessSnapshotIOS() {} + +bool ProcessSnapshotIOS::Initialize() { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + if (gettimeofday(&snapshot_time_, nullptr) != 0) { + PLOG(ERROR) << "gettimeofday"; + return false; + } + + InitializeModules(); + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +pid_t ProcessSnapshotIOS::ProcessID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return getpid(); +} + +pid_t ProcessSnapshotIOS::ParentProcessID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return 0; +} + +void ProcessSnapshotIOS::SnapshotTime(timeval* snapshot_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *snapshot_time = snapshot_time_; +} + +void ProcessSnapshotIOS::ProcessStartTime(timeval* start_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); +} + +void ProcessSnapshotIOS::ProcessCPUTimes(timeval* user_time, + timeval* system_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); +} + +void ProcessSnapshotIOS::ReportID(UUID* report_id) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *report_id = report_id_; +} + +void ProcessSnapshotIOS::ClientID(UUID* client_id) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *client_id = client_id_; +} + +const std::map<std::string, std::string>& +ProcessSnapshotIOS::AnnotationsSimpleMap() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return annotations_simple_map_; +} + +const SystemSnapshot* ProcessSnapshotIOS::System() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return nullptr; +} + +std::vector<const ThreadSnapshot*> ProcessSnapshotIOS::Threads() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<const ThreadSnapshot*>(); +} + +std::vector<const ModuleSnapshot*> ProcessSnapshotIOS::Modules() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + std::vector<const ModuleSnapshot*> modules; + for (const auto& module : modules_) { + modules.push_back(module.get()); + } + return modules; +} + +std::vector<UnloadedModuleSnapshot> ProcessSnapshotIOS::UnloadedModules() + const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<UnloadedModuleSnapshot>(); +} + +const ExceptionSnapshot* ProcessSnapshotIOS::Exception() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return nullptr; +} + +std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotIOS::MemoryMap() + const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<const MemoryMapRegionSnapshot*>(); +} + +std::vector<HandleSnapshot> ProcessSnapshotIOS::Handles() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<HandleSnapshot>(); +} + +std::vector<const MemorySnapshot*> ProcessSnapshotIOS::ExtraMemory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<const MemorySnapshot*>(); +} + +const ProcessMemory* ProcessSnapshotIOS::Memory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return nullptr; +} + +void ProcessSnapshotIOS::InitializeModules() { + const dyld_all_image_infos* image_infos = + internal::ModuleSnapshotIOS::DyldAllImageInfo(); + + uint32_t image_count = image_infos->infoArrayCount; + const dyld_image_info* image_array = image_infos->infoArray; + for (uint32_t image_index = 0; image_index < image_count; ++image_index) { + const dyld_image_info* image = &image_array[image_index]; + auto module = std::make_unique<internal::ModuleSnapshotIOS>(); + if (module->Initialize(image)) { + modules_.push_back(std::move(module)); + } + } + auto module = std::make_unique<internal::ModuleSnapshotIOS>(); + if (module->InitializeDyld(image_infos)) { + modules_.push_back(std::move(module)); + } +} + +} // namespace crashpad diff --git a/snapshot/ios/process_snapshot_ios.h b/snapshot/ios/process_snapshot_ios.h new file mode 100644 index 00000000..4ebcaf13 --- /dev/null +++ b/snapshot/ios/process_snapshot_ios.h @@ -0,0 +1,75 @@ +// 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_IOS_PROCESS_SNAPSHOT_IOS_H_ +#define CRASHPAD_SNAPSHOT_IOS_PROCESS_SNAPSHOT_IOS_H_ + +#include <vector> + +#include "snapshot/ios/module_snapshot_ios.h" +#include "snapshot/process_snapshot.h" +#include "snapshot/unloaded_module_snapshot.h" + +namespace crashpad { + +//! \brief A ProcessSnapshot of a running (or crashed) process running on a +//! iphoneOS system. +class ProcessSnapshotIOS final : public ProcessSnapshot { + public: + ProcessSnapshotIOS(); + ~ProcessSnapshotIOS() override; + + //! \brief Initializes the object. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! an appropriate message logged. + bool Initialize(); + + // ProcessSnapshot: + pid_t ProcessID() const override; + pid_t ParentProcessID() const override; + void SnapshotTime(timeval* snapshot_time) const override; + void ProcessStartTime(timeval* start_time) const override; + void ProcessCPUTimes(timeval* user_time, timeval* system_time) const override; + void ReportID(UUID* report_id) const override; + void ClientID(UUID* client_id) const override; + const std::map<std::string, std::string>& AnnotationsSimpleMap() + const override; + const SystemSnapshot* System() const override; + std::vector<const ThreadSnapshot*> Threads() const override; + std::vector<const ModuleSnapshot*> Modules() const override; + std::vector<UnloadedModuleSnapshot> UnloadedModules() const override; + const ExceptionSnapshot* Exception() const override; + std::vector<const MemoryMapRegionSnapshot*> MemoryMap() const override; + std::vector<HandleSnapshot> Handles() const override; + std::vector<const MemorySnapshot*> ExtraMemory() const override; + const ProcessMemory* Memory() const override; + + private: + // Initializes modules_ on behalf of Initialize(). + void InitializeModules(); + + std::vector<std::unique_ptr<internal::ModuleSnapshotIOS>> modules_; + UUID report_id_; + UUID client_id_; + std::map<std::string, std::string> annotations_simple_map_; + timeval snapshot_time_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ProcessSnapshotIOS); +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_IOS_PROCESS_SNAPSHOT_IOS_H_ From 1d75af9bf5918fa1c365a4ac696f038e6028a30b Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Tue, 10 Mar 2020 16:16:21 -0400 Subject: [PATCH 351/401] Fix bad iOS module casting. Change-Id: I0f8dcd867c56c4b1476c23d280e08448d2e90795 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2097177 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- snapshot/ios/module_snapshot_ios.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/snapshot/ios/module_snapshot_ios.cc b/snapshot/ios/module_snapshot_ios.cc index 824ad8a5..8b251eb9 100644 --- a/snapshot/ios/module_snapshot_ios.cc +++ b/snapshot/ios/module_snapshot_ios.cc @@ -87,25 +87,26 @@ bool ModuleSnapshotIOS::FinishInitialization() { cmd_index <= header->ncmds && cumulative_cmd_size < header->sizeofcmds; ++cmd_index, cumulative_cmd_size += command->cmdsize) { if (command->cmd == LC_SEGMENT_64) { - segment_command_64* segment = - reinterpret_cast<segment_command_64*>(&command); + const segment_command_64* segment = + reinterpret_cast<const segment_command_64*>(command); if (strcmp(segment->segname, SEG_TEXT) == 0) { size_ = segment->vmsize; } } else if (command->cmd == LC_ID_DYLIB) { - dylib_command* dylib = reinterpret_cast<dylib_command*>(&command); + const dylib_command* dylib = + reinterpret_cast<const dylib_command*>(command); dylib_version_ = dylib->dylib.current_version; } else if (command->cmd == LC_SOURCE_VERSION) { - source_version_command* source_version = - reinterpret_cast<source_version_command*>(&command); + const source_version_command* source_version = + reinterpret_cast<const source_version_command*>(command); source_version_ = source_version->version; } else if (command->cmd == LC_UUID) { - uuid_command* uuid = reinterpret_cast<uuid_command*>(&command); + const uuid_command* uuid = reinterpret_cast<const uuid_command*>(command); uuid_.InitializeFromBytes(uuid->uuid); } command = reinterpret_cast<const load_command*>( - reinterpret_cast<const uint8_t*>(command + command->cmdsize)); + reinterpret_cast<const uint8_t*>(command) + command->cmdsize); // TODO(justincohen): Warn-able things: // - Bad Mach-O magic (and give up trying to process the module) From 6835b8e29db1877e94efb2c2c76380ca9795216a Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Fri, 13 Mar 2020 11:24:26 -0400 Subject: [PATCH 352/401] Roll buildtools/ afc5b798c..4164a3056 (9 commits) https://chromium.googlesource.com/chromium/src/buildtools.git/+log/afc5b798c729..4164a3056267 $ git log afc5b798c..4164a3056 --date=short --no-merges --format='%ad %ae %s' 2020-03-12 agrieve Roll GN from fd3d768b..9499562d 2020-03-10 thakis roll gn 4166e9fbc1f..fd3d768bcfd4 2020-02-29 xiaohuic Clean up buildtools repo migration code 2020-02-24 thakis Revert "Roll libunwind 43bb9f8722..d999d54f4b" 2020-02-21 thakis Roll libunwind 43bb9f8722..d999d54f4b 2020-02-21 seblalancette Roll GN from 97cc440d..4166e9fb 2020-02-21 bpastene Reland: Pull libunwind, libcxx, libcxxabi from a different mirror. 2020-02-19 bpastene Revert "Pull libunwind, libcxx, libcxxabi from a different mirror." 2020-02-19 thakis Pull libunwind, libcxx, libcxxabi from a different mirror. Created with: roll-dep buildtools Change-Id: Iedee7c3de93c08999b6da8ed8c31cc2c651c5c54 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2102907 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index f7355b78..8b958f18 100644 --- a/DEPS +++ b/DEPS @@ -25,7 +25,7 @@ vars = { deps = { 'buildtools': Var('chromium_git') + '/chromium/src/buildtools.git@' + - 'afc5b798c72905e85f9991152be878714c579958', + '4164a305626786b1912d467003acf4c4995bec7d', 'crashpad/third_party/edo/edo': { 'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git@' + '243fc89ae95b24717d41f3786f6a9abeeef87c92', From 9a31d3f8e9815774026a753a1ff6155347cd549f Mon Sep 17 00:00:00 2001 From: John Bauman <jbauman@google.com> Date: Fri, 13 Mar 2020 13:45:15 -0700 Subject: [PATCH 353/401] Print thread state after failure to suspend This may help us debug some issues where the thread is failing to suspend. Bug: b/151318587 Change-Id: I0d2d539f769ebb1cdd71606e1d23d8fa66673879 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2103411 Commit-Queue: John Bauman <jbauman@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- util/fuchsia/scoped_task_suspend.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/util/fuchsia/scoped_task_suspend.cc b/util/fuchsia/scoped_task_suspend.cc index 4b4ffe74..8591d558 100644 --- a/util/fuchsia/scoped_task_suspend.cc +++ b/util/fuchsia/scoped_task_suspend.cc @@ -41,7 +41,7 @@ ScopedTaskSuspend::ScopedTaskSuspend(const zx::process& process) { for (const auto& thread : GetThreadHandles(process)) { // We omit the crashed thread (blocked in an exception) as it is technically // not suspended, cf. ZX-3772. - zx_info_thread info; + zx_info_thread_t info; if (thread.get_info( ZX_INFO_THREAD, &info, sizeof(info), nullptr, nullptr) == ZX_OK) { if (info.state == ZX_THREAD_STATE_BLOCKED_EXCEPTION) { @@ -52,8 +52,16 @@ ScopedTaskSuspend::ScopedTaskSuspend(const zx::process& process) { zx_signals_t observed = 0u; const zx_status_t wait_status = thread.wait_one( ZX_THREAD_SUSPENDED, zx::deadline_after(zx::msec(50)), &observed); - ZX_LOG_IF(ERROR, wait_status != ZX_OK, wait_status) - << "thread failed to suspend"; + if (wait_status != ZX_OK) { + zx_info_thread_t info = {}; + zx_status_t info_status = thread.get_info( + ZX_INFO_THREAD, &info, sizeof(info), nullptr, nullptr); + ZX_LOG(ERROR, wait_status) << "thread failed to suspend"; + LOG(ERROR) << "Thread info status " << info_status; + if (info_status == ZX_OK) { + LOG(ERROR) << "Thread state " << info.state; + } + } } } From 4e2a190ad6e6674c1dafed858f603b32a2344e52 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Fri, 20 Mar 2020 10:37:01 -0400 Subject: [PATCH 354/401] [ios] Bring up first draft thread and memory snapshot. Gather most of the necessary information for the thread snapshot. Note that: - The 'capture' portion of this CL will be moved out of the snapshot interface and into a separate in-process dump to disk location. - All of the pointer dereferences need to be wrapped in vm_read. - The read-fast-and-dump logic in thread_snapshot may end up in a different file completely, but until we pick a serialization/deserialization method, keep it as-is. Change-Id: I80ba323cb6a59ac0dd1bba9150d047ba83cc4dad Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2085572 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Justin Cohen <justincohen@chromium.org> --- snapshot/BUILD.gn | 6 + snapshot/ios/memory_snapshot_ios.cc | 65 ++++ snapshot/ios/memory_snapshot_ios.h | 63 ++++ snapshot/ios/process_snapshot_ios.cc | 27 +- snapshot/ios/process_snapshot_ios.h | 6 + snapshot/ios/thread_snapshot_ios.cc | 472 +++++++++++++++++++++++++++ snapshot/ios/thread_snapshot_ios.h | 77 +++++ snapshot/mac/cpu_context_mac.cc | 26 ++ snapshot/mac/cpu_context_mac.h | 11 + 9 files changed, 752 insertions(+), 1 deletion(-) create mode 100644 snapshot/ios/memory_snapshot_ios.cc create mode 100644 snapshot/ios/memory_snapshot_ios.h create mode 100644 snapshot/ios/thread_snapshot_ios.cc create mode 100644 snapshot/ios/thread_snapshot_ios.h diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index bfee6f51..60cf1df2 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -110,10 +110,16 @@ static_library("snapshot") { if (crashpad_is_ios) { sources += [ + "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/thread_snapshot_ios.cc", + "ios/thread_snapshot_ios.h", + "mac/cpu_context_mac.cc", + "mac/cpu_context_mac.h", ] } diff --git a/snapshot/ios/memory_snapshot_ios.cc b/snapshot/ios/memory_snapshot_ios.cc new file mode 100644 index 00000000..e760465d --- /dev/null +++ b/snapshot/ios/memory_snapshot_ios.cc @@ -0,0 +1,65 @@ +// 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/ios/memory_snapshot_ios.h" + +namespace crashpad { +namespace internal { + +void MemorySnapshotIOS::Initialize(vm_address_t address, vm_size_t size) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + address_ = address; + size_ = base::checked_cast<size_t>(size); + + // TODO(justincohen): This is temporary, as MemorySnapshotIOS will likely be + // able to point directly to the deserialized data dump rather than copying + // data around. + buffer_ = std::unique_ptr<uint8_t[]>(new uint8_t[size_]); + memcpy(buffer_.get(), reinterpret_cast<void*>(address_), size_); + INITIALIZATION_STATE_SET_VALID(initialized_); +} + +uint64_t MemorySnapshotIOS::Address() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return address_; +} + +size_t MemorySnapshotIOS::Size() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return size_; +} + +bool MemorySnapshotIOS::Read(Delegate* delegate) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + if (size_ == 0) { + return delegate->MemorySnapshotDelegateRead(nullptr, size_); + } + + return delegate->MemorySnapshotDelegateRead(buffer_.get(), size_); +} + +const MemorySnapshot* MemorySnapshotIOS::MergeWithOtherSnapshot( + const MemorySnapshot* other) const { + CheckedRange<uint64_t, size_t> merged(0, 0); + if (!LoggingDetermineMergedRange(this, other, &merged)) + return nullptr; + + auto result = std::make_unique<MemorySnapshotIOS>(); + result->Initialize(merged.base(), merged.size()); + return result.release(); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/ios/memory_snapshot_ios.h b/snapshot/ios/memory_snapshot_ios.h new file mode 100644 index 00000000..be991056 --- /dev/null +++ b/snapshot/ios/memory_snapshot_ios.h @@ -0,0 +1,63 @@ +// 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_IOS_MEMORY_SNAPSHOT_IOS_H_ +#define CRASHPAD_SNAPSHOT_IOS_MEMORY_SNAPSHOT_IOS_H_ + +#include "base/macros.h" +#include "snapshot/memory_snapshot.h" +#include "util/misc/address_types.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { + +//! \brief A MemorySnapshot of a memory region. +class MemorySnapshotIOS final : public MemorySnapshot { + public: + MemorySnapshotIOS() = default; + ~MemorySnapshotIOS() = default; + + //! \brief Initializes the object. + //! + //! \param[in] address The base address of the memory region to snapshot. + //! \param[in] size The size of the memory region to snapshot. + void Initialize(vm_address_t address, vm_size_t size); + + // MemorySnapshot: + uint64_t Address() const override; + size_t Size() const override; + bool Read(Delegate* delegate) const override; + const MemorySnapshot* MergeWithOtherSnapshot( + const MemorySnapshot* other) const override; + + private: + template <class T> + friend const MemorySnapshot* MergeWithOtherSnapshotImpl( + const T* self, + const MemorySnapshot* other); + + // TODO(justincohen): This is temporary until deserialization is worked out. + std::unique_ptr<uint8_t[]> buffer_; + vm_address_t address_; + vm_size_t size_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(MemorySnapshotIOS); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_IOS_MEMORY_SNAPSHOT_IOS_H_ diff --git a/snapshot/ios/process_snapshot_ios.cc b/snapshot/ios/process_snapshot_ios.cc index 666fc198..27f9de4d 100644 --- a/snapshot/ios/process_snapshot_ios.cc +++ b/snapshot/ios/process_snapshot_ios.cc @@ -26,6 +26,7 @@ namespace crashpad { ProcessSnapshotIOS::ProcessSnapshotIOS() : ProcessSnapshot(), + threads_(), modules_(), report_id_(), client_id_(), @@ -43,6 +44,7 @@ bool ProcessSnapshotIOS::Initialize() { return false; } + InitializeThreads(); InitializeModules(); INITIALIZATION_STATE_SET_VALID(initialized_); @@ -96,7 +98,11 @@ const SystemSnapshot* ProcessSnapshotIOS::System() const { std::vector<const ThreadSnapshot*> ProcessSnapshotIOS::Threads() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return std::vector<const ThreadSnapshot*>(); + std::vector<const ThreadSnapshot*> threads; + for (const auto& thread : threads_) { + threads.push_back(thread.get()); + } + return threads; } std::vector<const ModuleSnapshot*> ProcessSnapshotIOS::Modules() const { @@ -140,6 +146,25 @@ const ProcessMemory* ProcessSnapshotIOS::Memory() const { return nullptr; } +void ProcessSnapshotIOS::InitializeThreads() { + mach_msg_type_number_t thread_count = 0; + const thread_act_array_t threads = + internal::ThreadSnapshotIOS::GetThreads(&thread_count); + for (uint32_t thread_index = 0; thread_index < thread_count; ++thread_index) { + thread_t thread = threads[thread_index]; + auto thread_snapshot = std::make_unique<internal::ThreadSnapshotIOS>(); + if (thread_snapshot->Initialize(thread)) { + threads_.push_back(std::move(thread_snapshot)); + } + mach_port_deallocate(mach_task_self(), thread); + } + // TODO(justincohen): This dealloc above and below needs to move with the + // call to task_threads inside internal::ThreadSnapshotIOS::GetThreads. + vm_deallocate(mach_task_self(), + reinterpret_cast<vm_address_t>(threads), + sizeof(thread_t) * thread_count); +} + void ProcessSnapshotIOS::InitializeModules() { const dyld_all_image_infos* image_infos = internal::ModuleSnapshotIOS::DyldAllImageInfo(); diff --git a/snapshot/ios/process_snapshot_ios.h b/snapshot/ios/process_snapshot_ios.h index 4ebcaf13..19d43b2e 100644 --- a/snapshot/ios/process_snapshot_ios.h +++ b/snapshot/ios/process_snapshot_ios.h @@ -18,7 +18,9 @@ #include <vector> #include "snapshot/ios/module_snapshot_ios.h" +#include "snapshot/ios/thread_snapshot_ios.h" #include "snapshot/process_snapshot.h" +#include "snapshot/thread_snapshot.h" #include "snapshot/unloaded_module_snapshot.h" namespace crashpad { @@ -60,6 +62,10 @@ class ProcessSnapshotIOS final : public ProcessSnapshot { // Initializes modules_ on behalf of Initialize(). void InitializeModules(); + // Initializes threads_ on behalf of Initialize(). + void InitializeThreads(); + + std::vector<std::unique_ptr<internal::ThreadSnapshotIOS>> threads_; std::vector<std::unique_ptr<internal::ModuleSnapshotIOS>> modules_; UUID report_id_; UUID client_id_; diff --git a/snapshot/ios/thread_snapshot_ios.cc b/snapshot/ios/thread_snapshot_ios.cc new file mode 100644 index 00000000..a5e96960 --- /dev/null +++ b/snapshot/ios/thread_snapshot_ios.cc @@ -0,0 +1,472 @@ +// 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/ios/thread_snapshot_ios.h" + +#include "base/mac/mach_logging.h" +#include "snapshot/mac/cpu_context_mac.h" + +namespace { + +#if defined(ARCH_CPU_X86_64) +const thread_state_flavor_t kThreadStateFlavor = x86_THREAD_STATE64; +const thread_state_flavor_t kFloatStateFlavor = x86_FLOAT_STATE64; +const thread_state_flavor_t kDebugStateFlavor = x86_DEBUG_STATE64; +#elif defined(ARCH_CPU_ARM64) +const thread_state_flavor_t kThreadStateFlavor = ARM_THREAD_STATE64; +const thread_state_flavor_t kFloatStateFlavor = ARM_NEON_STATE64; +#endif + +kern_return_t MachVMRegionRecurseDeepest(task_t task, + vm_address_t* address, + vm_size_t* size, + natural_t* depth, + vm_prot_t* protection, + unsigned int* user_tag) { + vm_region_submap_short_info_64 submap_info; + mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; + while (true) { + kern_return_t kr = vm_region_recurse_64( + task, + address, + size, + depth, + reinterpret_cast<vm_region_recurse_info_t>(&submap_info), + &count); + if (kr != KERN_SUCCESS) { + return kr; + } + + if (!submap_info.is_submap) { + *protection = submap_info.protection; + *user_tag = submap_info.user_tag; + return KERN_SUCCESS; + } + + ++*depth; + } +} + +//! \brief Adjusts the region for the red zone, if the ABI requires one. +//! +//! This method performs red zone calculation for CalculateStackRegion(). Its +//! parameters are local variables used within that method, and may be +//! modified as needed. +//! +//! Where a red zone is required, the region of memory captured for a thread’s +//! stack will be extended to include the red zone below the stack pointer, +//! provided that such memory is mapped, readable, and has the correct user +//! tag value. If these conditions cannot be met fully, as much of the red +//! zone will be captured as is possible while meeting these conditions. +//! +//! \param[in,out] start_address The base address of the region to begin +//! capturing stack memory from. On entry, \a start_address is the stack +//! pointer. On return, \a start_address may be decreased to encompass a +//! red zone. +//! \param[in,out] region_base The base address of the region that contains +//! stack memory. This is distinct from \a start_address in that \a +//! region_base will be page-aligned. On entry, \a region_base is the +//! base address of a region that contains \a start_address. On return, +//! if \a start_address is decremented and is outside of the region +//! originally described by \a region_base, \a region_base will also be +//! decremented appropriately. +//! \param[in,out] region_size The size of the region that contains stack +//! memory. This region begins at \a region_base. On return, if \a +//! region_base is decremented, \a region_size will be incremented +//! appropriately. +//! \param[in] user_tag The Mach VM system’s user tag for the region described +//! by the initial values of \a region_base and \a region_size. The red +//! zone will only be allowed to extend out of the region described by +//! these initial values if the user tag is appropriate for stack memory +//! and the expanded region has the same user tag value. +void LocateRedZone(vm_address_t* const start_address, + vm_address_t* const region_base, + vm_address_t* const region_size, + const unsigned int user_tag) { + // x86_64 has a red zone. See AMD64 ABI 0.99.8, + // https://raw.githubusercontent.com/wiki/hjl-tools/x86-psABI/x86-64-psABI-r252.pdf#page=19, + // section 3.2.2, “The Stack Frame”. + // So does ARM64, + // https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html + // section "Red Zone". + constexpr vm_size_t kRedZoneSize = 128; + vm_address_t red_zone_base = + *start_address >= kRedZoneSize ? *start_address - kRedZoneSize : 0; + bool red_zone_ok = false; + if (red_zone_base >= *region_base) { + // The red zone is within the region already discovered. + red_zone_ok = true; + } else if (red_zone_base < *region_base && user_tag == VM_MEMORY_STACK) { + // Probe to see if there’s a region immediately below the one already + // discovered. + vm_address_t red_zone_region_base = red_zone_base; + vm_size_t red_zone_region_size; + natural_t red_zone_depth = 0; + vm_prot_t red_zone_protection; + unsigned int red_zone_user_tag; + kern_return_t kr = MachVMRegionRecurseDeepest(mach_task_self(), + &red_zone_region_base, + &red_zone_region_size, + &red_zone_depth, + &red_zone_protection, + &red_zone_user_tag); + if (kr != KERN_SUCCESS) { + MACH_LOG(INFO, kr) << "vm_region_recurse"; + *start_address = *region_base; + } else if (red_zone_region_base + red_zone_region_size == *region_base && + (red_zone_protection & VM_PROT_READ) != 0 && + red_zone_user_tag == user_tag) { + // The region containing the red zone is immediately below the region + // already found, it’s readable (not the guard region), and it has the + // same user tag as the region already found, so merge them. + red_zone_ok = true; + *region_base -= red_zone_region_size; + *region_size += red_zone_region_size; + } + } + + if (red_zone_ok) { + // Begin capturing from the base of the red zone (but not the entire + // region that encompasses the red zone). + *start_address = red_zone_base; + } else { + // The red zone would go lower into another region in memory, but no + // region was found. Memory can only be captured to an address as low as + // the base address of the region already found. + *start_address = *region_base; + } +} + +//! \brief Calculates the base address and size of the region used as a +//! thread’s stack. +//! +//! The region returned by this method may be formed by merging multiple +//! adjacent regions in a process’ memory map if appropriate. The base address +//! of the returned region may be lower than the \a stack_pointer passed in +//! when the ABI mandates a red zone below the stack pointer. +//! +//! \param[in] stack_pointer The stack pointer, referring to the top (lowest +//! address) of a thread’s stack. +//! \param[out] stack_region_size The size of the memory region used as the +//! thread’s stack. +//! +//! \return The base address (lowest address) of the memory region used as the +//! thread’s stack. +vm_address_t CalculateStackRegion(vm_address_t stack_pointer, + vm_size_t* stack_region_size) { + // For pthreads, it may be possible to compute the stack region based on the + // internal _pthread::stackaddr and _pthread::stacksize. The _pthread struct + // for a thread can be located at TSD slot 0, or the known offsets of + // stackaddr and stacksize from the TSD area could be used. + vm_address_t region_base = stack_pointer; + vm_size_t region_size; + natural_t depth = 0; + vm_prot_t protection; + unsigned int user_tag; + kern_return_t kr = MachVMRegionRecurseDeepest(mach_task_self(), + ®ion_base, + ®ion_size, + &depth, + &protection, + &user_tag); + if (kr != KERN_SUCCESS) { + MACH_LOG(INFO, kr) << "mach_vm_region_recurse"; + *stack_region_size = 0; + return 0; + } + + if (region_base > stack_pointer) { + // There’s nothing mapped at the stack pointer’s address. Something may have + // trashed the stack pointer. Note that this shouldn’t happen for a normal + // stack guard region violation because the guard region is mapped but has + // VM_PROT_NONE protection. + *stack_region_size = 0; + return 0; + } + + vm_address_t start_address = stack_pointer; + + if ((protection & VM_PROT_READ) == 0) { + // If the region isn’t readable, the stack pointer probably points to the + // guard region. Don’t include it as part of the stack, and don’t include + // anything at any lower memory address. The code below may still possibly + // find the real stack region at a memory address higher than this region. + start_address = region_base + region_size; + } else { + // If the ABI requires a red zone, adjust the region to include it if + // possible. + LocateRedZone(&start_address, ®ion_base, ®ion_size, user_tag); + + // Regardless of whether the ABI requires a red zone, capture up to + // kExtraCaptureSize additional bytes of stack, but only if present in the + // region that was already found. + constexpr vm_size_t kExtraCaptureSize = 128; + start_address = std::max(start_address >= kExtraCaptureSize + ? start_address - kExtraCaptureSize + : start_address, + region_base); + + // Align start_address to a 16-byte boundary, which can help readers by + // ensuring that data is aligned properly. This could page-align instead, + // but that might be wasteful. + constexpr vm_size_t kDesiredAlignment = 16; + start_address &= ~(kDesiredAlignment - 1); + DCHECK_GE(start_address, region_base); + } + + region_size -= (start_address - region_base); + region_base = start_address; + + vm_size_t total_region_size = region_size; + + // The stack region may have gotten split up into multiple abutting regions. + // Try to coalesce them. This frequently happens for the main thread’s stack + // when setrlimit(RLIMIT_STACK, …) is called. It may also happen if a region + // is split up due to an mprotect() or vm_protect() call. + // + // Stack regions created by the kernel and the pthreads library will be marked + // with the VM_MEMORY_STACK user tag. Scanning for multiple adjacent regions + // with the same tag should find an entire stack region. Checking that the + // protection on individual regions is not VM_PROT_NONE should guarantee that + // this algorithm doesn’t collect map entries belonging to another thread’s + // stack: well-behaved stacks (such as those created by the kernel and the + // pthreads library) have VM_PROT_NONE guard regions at their low-address + // ends. + // + // Other stack regions may not be so well-behaved and thus if user_tag is not + // VM_MEMORY_STACK, the single region that was found is used as-is without + // trying to merge it with other adjacent regions. + if (user_tag == VM_MEMORY_STACK) { + vm_address_t try_address = region_base; + vm_address_t original_try_address; + + while (try_address += region_size, + original_try_address = try_address, + (kr = MachVMRegionRecurseDeepest(mach_task_self(), + &try_address, + ®ion_size, + &depth, + &protection, + &user_tag) == KERN_SUCCESS) && + try_address == original_try_address && + (protection & VM_PROT_READ) != 0 && + user_tag == VM_MEMORY_STACK) { + total_region_size += region_size; + } + + if (kr != KERN_SUCCESS && kr != KERN_INVALID_ADDRESS) { + // Tolerate KERN_INVALID_ADDRESS because it will be returned when there + // are no more regions in the map at or above the specified |try_address|. + MACH_LOG(INFO, kr) << "vm_region_recurse"; + } + } + + *stack_region_size = total_region_size; + return region_base; +} + +} // namespace + +namespace crashpad { +namespace internal { + +ThreadSnapshotIOS::ThreadSnapshotIOS() + : ThreadSnapshot(), + context_(), + stack_(), + thread_id_(0), + thread_specific_data_address_(0), + suspend_count_(0), + priority_(0), + initialized_() {} + +ThreadSnapshotIOS::~ThreadSnapshotIOS() {} + +// static +thread_act_array_t ThreadSnapshotIOS::GetThreads( + mach_msg_type_number_t* count) { + thread_act_array_t threads; + kern_return_t kr = task_threads(mach_task_self(), &threads, count); + if (kr != KERN_SUCCESS) { + MACH_LOG(WARNING, kr) << "task_threads"; + } + return threads; +} + +bool ThreadSnapshotIOS::Initialize(thread_t thread) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + // TODO(justincohen): Move the following thread_get_state, thread_get_info, + // thread_policy_get and CalculateStackRegion to the serialize-on-read + // section. + thread_basic_info basic_info; + thread_precedence_policy precedence; + vm_size_t stack_region_size; + vm_address_t stack_region_address; +#if defined(ARCH_CPU_X86_64) + x86_thread_state64_t thread_state; + x86_float_state64_t float_state; + x86_debug_state64_t debug_state; + mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT; + mach_msg_type_number_t float_state_count = x86_FLOAT_STATE64_COUNT; + mach_msg_type_number_t debug_state_count = x86_DEBUG_STATE64_COUNT; +#elif defined(ARCH_CPU_ARM64) + arm_thread_state64_t thread_state; + arm_neon_state64_t float_state; + mach_msg_type_number_t thread_state_count = ARM_THREAD_STATE64_COUNT; + mach_msg_type_number_t float_state_count = ARM_NEON_STATE64_COUNT; +#endif + + kern_return_t kr = + thread_get_state(thread, + kThreadStateFlavor, + reinterpret_cast<thread_state_t>(&thread_state), + &thread_state_count); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "thread_get_state(" << kThreadStateFlavor << ")"; + } + + kr = thread_get_state(thread, + kFloatStateFlavor, + reinterpret_cast<thread_state_t>(&float_state), + &float_state_count); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "thread_get_state(" << kFloatStateFlavor << ")"; + } + +#if defined(ARCH_CPU_X86_64) + kr = thread_get_state(thread, + kDebugStateFlavor, + reinterpret_cast<thread_state_t>(&debug_state), + &debug_state_count); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "thread_get_state(" << kDebugStateFlavor << ")"; + } +#endif + + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + kr = thread_info(thread, + THREAD_BASIC_INFO, + reinterpret_cast<thread_info_t>(&basic_info), + &count); + if (kr != KERN_SUCCESS) { + MACH_LOG(WARNING, kr) << "thread_info(THREAD_BASIC_INFO)"; + } + + thread_identifier_info identifier_info; + count = THREAD_IDENTIFIER_INFO_COUNT; + kr = thread_info(thread, + THREAD_IDENTIFIER_INFO, + reinterpret_cast<thread_info_t>(&identifier_info), + &count); + if (kr != KERN_SUCCESS) { + MACH_LOG(WARNING, kr) << "thread_info(THREAD_IDENTIFIER_INFO)"; + } + + count = THREAD_PRECEDENCE_POLICY_COUNT; + boolean_t get_default = FALSE; + kr = thread_policy_get(thread, + THREAD_PRECEDENCE_POLICY, + reinterpret_cast<thread_policy_t>(&precedence), + &count, + &get_default); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "thread_policy_get"; + } + +#if defined(ARCH_CPU_X86_64) + vm_address_t stack_pointer = thread_state.__rsp; +#elif defined(ARCH_CPU_ARM64) + vm_address_t stack_pointer = thread_state.__sp; +#endif + stack_region_address = + CalculateStackRegion(stack_pointer, &stack_region_size); + + // TODO(justincohen): Assume the following will fill in snapshot data from + // a deserialized object. + thread_id_ = identifier_info.thread_id; + suspend_count_ = basic_info.suspend_count; + priority_ = precedence.importance; + + // thread_identifier_info::thread_handle contains the base of the + // thread-specific data area, which on x86 and x86_64 is the thread’s base + // address of the %gs segment. 10.9.2 xnu-2422.90.20/osfmk/kern/thread.c + // thread_info_internal() gets the value from + // machine_thread::cthread_self, which is the same value used to set the + // %gs base in xnu-2422.90.20/osfmk/i386/pcb_native.c + // act_machine_switch_pcb(). + // + // On ARM64 10.15.0 xnu-6153.11.26/osfmk/kern/thread.c, it sets + // thread_identifier_info_t::thread_handle to + // thread->machine.cthread_self, which is set to tsd_base in + // osfmk/arm64/pcb.c. + thread_specific_data_address_ = identifier_info.thread_handle; + stack_.Initialize(stack_region_address, stack_region_size); + +#if defined(ARCH_CPU_X86_64) + context_.architecture = kCPUArchitectureX86_64; + context_.x86_64 = &context_x86_64_; + InitializeCPUContextX86_64(&context_x86_64_, + THREAD_STATE_NONE, + nullptr, + 0, + &thread_state, + &float_state, + &debug_state); +#elif defined(ARCH_CPU_ARM64) + context_.architecture = kCPUArchitectureARM64; + context_.arm64 = &context_arm64_; + InitializeCPUContextARM64(&context_arm64_, &thread_state, &float_state); +#endif + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +const CPUContext* ThreadSnapshotIOS::Context() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return &context_; +} + +const MemorySnapshot* ThreadSnapshotIOS::Stack() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return &stack_; +} + +uint64_t ThreadSnapshotIOS::ThreadID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_id_; +} + +int ThreadSnapshotIOS::SuspendCount() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return suspend_count_; +} + +int ThreadSnapshotIOS::Priority() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return priority_; +} + +uint64_t ThreadSnapshotIOS::ThreadSpecificDataAddress() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_specific_data_address_; +} + +std::vector<const MemorySnapshot*> ThreadSnapshotIOS::ExtraMemory() const { + return std::vector<const MemorySnapshot*>(); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/ios/thread_snapshot_ios.h b/snapshot/ios/thread_snapshot_ios.h new file mode 100644 index 00000000..c6dde7e6 --- /dev/null +++ b/snapshot/ios/thread_snapshot_ios.h @@ -0,0 +1,77 @@ +// 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_IOS_THREAD_SNAPSHOT_IOS_H_ +#define CRASHPAD_SNAPSHOT_IOS_THREAD_SNAPSHOT_IOS_H_ + +#include "base/macros.h" +#include "build/build_config.h" +#include "snapshot/cpu_context.h" +#include "snapshot/ios/memory_snapshot_ios.h" +#include "snapshot/thread_snapshot.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { +namespace internal { + +//! \brief A ThreadSnapshot of a thread on an iOS system. +class ThreadSnapshotIOS final : public ThreadSnapshot { + public: + ThreadSnapshotIOS(); + ~ThreadSnapshotIOS() override; + + //! \brief Initializes the object. + //! + //! \brief thread The mach thread used to initialize this object. + bool Initialize(thread_t thread); + + //! \brief Returns an array of thread_t threads. + //! + //! \param[out] count The number of threads returned. + //! + //! \return An array of of size \a count threads. + static thread_act_array_t GetThreads(mach_msg_type_number_t* count); + + // ThreadSnapshot: + const CPUContext* Context() const override; + const MemorySnapshot* Stack() const override; + uint64_t ThreadID() const override; + int SuspendCount() const override; + int Priority() const override; + uint64_t ThreadSpecificDataAddress() const override; + std::vector<const MemorySnapshot*> ExtraMemory() const override; + + private: +#if defined(ARCH_CPU_X86_64) + CPUContextX86_64 context_x86_64_; +#elif defined(ARCH_CPU_ARM64) + CPUContextARM64 context_arm64_; +#else +#error Port. +#endif // ARCH_CPU_X86_64 + CPUContext context_; + MemorySnapshotIOS stack_; + uint64_t thread_id_; + uint64_t thread_specific_data_address_; + int suspend_count_; + int priority_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ThreadSnapshotIOS); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_IOS_THREAD_SNAPSHOT_IOS_H_ diff --git a/snapshot/mac/cpu_context_mac.cc b/snapshot/mac/cpu_context_mac.cc index c91e3318..acec60ec 100644 --- a/snapshot/mac/cpu_context_mac.cc +++ b/snapshot/mac/cpu_context_mac.cc @@ -436,6 +436,32 @@ void InitializeCPUContextX86_64(CPUContextX86_64* context, } // namespace internal +#elif defined(ARCH_CPU_ARM_FAMILY) + +namespace internal { + +void InitializeCPUContextARM64(CPUContextARM64* context, + const arm_thread_state64_t* arm_thread_state64, + const arm_neon_state64_t* arm_neon_state64) { + // The structures of context->regs and arm_thread_state64->__x are laid out + // identically for this copy, even though the members are organized + // differently. Because of this difference, there can't be a static assert + // similar to the one below for fpsimd. + memcpy(context->regs, arm_thread_state64->__x, sizeof(context->regs)); + context->sp = arm_thread_state64->__sp; + context->pc = arm_thread_state64->__pc; + context->spsr = + static_cast<decltype(context->spsr)>(arm_thread_state64->__cpsr); + + static_assert(sizeof(context->fpsimd) == sizeof(arm_neon_state64->__v), + "fpsimd context size mismatch"); + memcpy(context->fpsimd, arm_neon_state64->__v, sizeof(arm_neon_state64->__v)); + context->fpsr = arm_neon_state64->__fpsr; + context->fpcr = arm_neon_state64->__fpcr; +} + +} // namespace internal + #endif } // namespace crashpad diff --git a/snapshot/mac/cpu_context_mac.h b/snapshot/mac/cpu_context_mac.h index 30281c16..77aedb6b 100644 --- a/snapshot/mac/cpu_context_mac.h +++ b/snapshot/mac/cpu_context_mac.h @@ -108,6 +108,17 @@ void InitializeCPUContextX86_64(CPUContextX86_64* context, const x86_float_state64_t* x86_float_state64, const x86_debug_state64_t* x86_debug_state64); +#elif defined(ARCH_CPU_ARM_FAMILY) || DOXYGEN +//! \brief Initializes a CPUContextARM64 structure from native context +//! structures. +//! +//! \param[out] context The CPUContextARM64 structure to initialize. +//! \param[in] arm_thread_state64 The state of the thread’s integer registers. +//! \param[in] arm_neon_state64 The state of the thread’s floating-point +//! registers. +void InitializeCPUContextARM64(CPUContextARM64* context, + const arm_thread_state64_t* arm_thread_state64, + const arm_neon_state64_t* arm_neon_state64); #endif } // namespace internal From 296501351816448182af26c5f51c41e1a0ff7bea Mon Sep 17 00:00:00 2001 From: Nico Weber <thakis@chromium.org> Date: Mon, 23 Mar 2020 14:59:21 -0400 Subject: [PATCH 355/401] Prepare crashpad mig stuff for -Wunreachable-code in chromium_code. Bug: chromium:346399 Change-Id: I5d93a2f6781dd4dd3483009d9c470050d490be3c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2116252 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org> --- util/BUILD.gn | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index aa890264..bd0d2427 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -75,6 +75,17 @@ if (crashpad_is_mac) { rebase_path("../compat/mac", root_build_dir), ] } + + source_set("mig_output") { + deps = [ ":mig" ] + sources = get_target_outputs(":mig") + if (crashpad_is_in_chromium) { + # mig output contains unreachable code, which irks -Wunreachable-code. + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + } + public_configs = [ "..:crashpad_config" ] + } } static_library("util") { @@ -281,7 +292,6 @@ static_library("util") { "process/process_memory_mac.h", "synchronization/semaphore_mac.cc", ] - sources += get_target_outputs(":mig") } deps = [] @@ -483,7 +493,7 @@ static_library("util") { "IOKit.framework", ] deps += [ - ":mig", + ":mig_output", "../third_party/apple_cf:apple_cf", ] include_dirs += [ "$root_build_dir/gen" ] From af2be80bdb8a21b8b6bd521f50844010fcc2becc Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 23 Mar 2020 13:26:03 -0700 Subject: [PATCH 356/401] android: configure a native test suite Most Android tests in Chromium's infrastructure are launched from an APK, but that's not appropriate for Crashpad where many things expect to be run in a plain executable. Bug: chromium:1050178 Change-Id: I6eeb3f5e4889193e5bbe2a3bad2cd99a18e970ba Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2112342 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- BUILD.gn | 24 ++++++++++++++++++++++++ test/gtest_main.cc | 2 ++ test/test_paths.cc | 5 +++++ 3 files changed, 31 insertions(+) diff --git a/BUILD.gn b/BUILD.gn index 3d0dc265..17c380e5 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -52,6 +52,30 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { # TODO(fuchsia:46559): Fix the leaks and remove this. deps += [ "//build/config/sanitizers:suppress-lsan.DO-NOT-USE-THIS" ] } + if (crashpad_is_android) { + use_raw_android_executable = true + + copy("crashpad_test_data") { + testonly = true + sources = [ + "test/test_paths_test_data_root.txt", + "util/net/testdata/ascii_http_body.txt", + "util/net/testdata/binary_http_body.dat", + ] + + outputs = [ + "$root_out_dir/crashpad_test_data/{{source}}", + ] + } + + deps += [ ":crashpad_test_data" ] + + extra_dist_files = [ + "$root_out_dir/crashpad_handler", + "$root_out_dir/crashpad_test_test_multiprocess_exec_test_child", + "$root_out_dir/crashpad_test_data", + ] + } } if (crashpad_is_in_fuchsia) { diff --git a/test/gtest_main.cc b/test/gtest_main.cc index 34394ad4..ad3a095e 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -73,6 +73,8 @@ int main(int argc, char* argv[]) { // runner. const bool use_chromium_test_launcher = !crashpad::test::WinChildProcess::IsChildProcess(); +#elif defined(OS_ANDROID) + constexpr bool use_chromium_test_launcher = false; #else // OS_WIN constexpr bool use_chromium_test_launcher = true; #endif // OS_WIN diff --git a/test/test_paths.cc b/test/test_paths.cc index 10bae7a2..dfe6c96b 100644 --- a/test/test_paths.cc +++ b/test/test_paths.cc @@ -69,10 +69,15 @@ base::FilePath TestDataRootInternal() { // out/{Debug,Release} relative to the Crashpad root. base::FilePath executable_path; if (Paths::Executable(&executable_path)) { +#if defined(OS_ANDROID) + base::FilePath candidate = executable_path.DirName() + .Append("crashpad_test_data"); +#else base::FilePath candidate = base::FilePath(executable_path.DirName() .Append(base::FilePath::kParentDirectory) .Append(base::FilePath::kParentDirectory)); +#endif if (IsTestDataRoot(candidate)) { return candidate; } From b75c5783735e83f21fac01a03d7a57673c51bbb8 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Tue, 24 Mar 2020 13:26:59 -0700 Subject: [PATCH 357/401] linux: disable arguments test on old kernels Bug: chromium:1050178 Change-Id: Ideafa5971cbaf76fa6865f671158958e7abb3a8c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2117366 Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/posix/process_info_test.cc | 35 +++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/util/posix/process_info_test.cc b/util/posix/process_info_test.cc index 6154ef70..69390fae 100644 --- a/util/posix/process_info_test.cc +++ b/util/posix/process_info_test.cc @@ -14,6 +14,7 @@ #include "util/posix/process_info.h" +#include <sys/utsname.h> #include <time.h> #include <algorithm> @@ -21,6 +22,7 @@ #include <string> #include <vector> +#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "gtest/gtest.h" @@ -29,6 +31,7 @@ #include "test/multiprocess.h" #include "util/file/file_io.h" #include "util/misc/implicit_cast.h" +#include "util/string/split_string.h" #if defined(OS_LINUX) || defined(OS_ANDROID) #include "util/linux/direct_ptrace_connection.h" @@ -93,11 +96,39 @@ void TestProcessSelfOrClone(const ProcessInfo& process_info) { time(&now); EXPECT_LE(start_time.tv_sec, now); + const std::vector<std::string>& expect_argv = GetMainArguments(); + +#if defined(OS_ANDROID) || defined(OS_LINUX) + // Prior to Linux 4.2, the kernel only allowed reading a single page from + // /proc/<pid>/cmdline, causing any further arguments to be truncated. Disable + // testing arguments in this case. + // TODO(jperaza): The main arguments are stored on the main thread's stack + // (and so should be included in dumps automatically), and + // ProcessInfo::Arguments() might be updated to read the arguments directly, + // rather than via procfs on older kernels. + utsname uts; + ASSERT_EQ(uname(&uts), 0) << ErrnoMessage("uname"); + std::vector<std::string> parts = SplitString(uts.release, '.'); + ASSERT_GE(parts.size(), 2u); + + int major, minor; + ASSERT_TRUE(base::StringToInt(parts[0], &major)); + ASSERT_TRUE(base::StringToInt(parts[1], &minor)); + + size_t argv_size = 0; + for (const auto& arg : expect_argv) { + argv_size += arg.size() + 1; + } + + if ((major < 4 || (major == 4 && minor < 2)) && + argv_size > static_cast<size_t>(getpagesize())) { + return; + } +#endif // OS_ANDROID || OS_LINUX + std::vector<std::string> argv; ASSERT_TRUE(process_info.Arguments(&argv)); - const std::vector<std::string>& expect_argv = GetMainArguments(); - // expect_argv always contains the initial view of the arguments at the time // the program was invoked. argv may contain this view, or it may contain the // current view of arguments after gtest argv processing. argv may be a subset From 311a5a2fdd5b6be8cee01b66991933397094204f Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Tue, 24 Mar 2020 16:53:56 -0400 Subject: [PATCH 358/401] Fix chromium build. Chromium's sources_assignment_filter broke the build. Change-Id: I741ce06feafcfe7abd69f65ad9c871b66452dd83 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2117368 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- snapshot/BUILD.gn | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 60cf1df2..0a118d0f 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -17,6 +17,9 @@ import("../build/crashpad_fuzzer_test.gni") if (crashpad_is_in_chromium) { import("//build/config/compiler/compiler.gni") + + # Prevent Chromium source assignment filters from being inherited. + set_sources_assignment_filter([]) } static_library("snapshot") { @@ -124,7 +127,6 @@ static_library("snapshot") { } if (crashpad_is_linux || crashpad_is_android) { - set_sources_assignment_filter([]) sources += [ "linux/cpu_context_linux.cc", "linux/cpu_context_linux.h", From d9c1ca1216fc278b671c7b5edaebf3a5d80609f9 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Wed, 25 Mar 2020 16:12:22 -0400 Subject: [PATCH 359/401] [ios] Bring up first draft system snapshot and iOS data collector. Gather most of the necessary information for the system snapshot. Note that: - The 'capture' portion of this CL will be moved out of the snapshot interface and into a separate in-process dump to disk location. - All of the pointer dereferences need to be wrapped in vm_read. - The read-fast-and-dump logic in thread_snapshot may end up in a different file completely, but until we pick a serialization/deserialization method, keep it as-is. Bug: crashpad:31 Change-Id: Iac82491fdb4a823163f02149f52a1e18e26fa9de Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2090173 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/BUILD.gn | 10 +- client/crashpad_client_ios.cc | 6 +- minidump/minidump_extensions.h | 3 +- minidump/minidump_system_info_writer.cc | 3 + snapshot/BUILD.gn | 2 + snapshot/ios/process_snapshot_ios.cc | 79 ++++++++- snapshot/ios/process_snapshot_ios.h | 27 ++- snapshot/ios/system_snapshot_ios.cc | 224 ++++++++++++++++++++++++ snapshot/ios/system_snapshot_ios.h | 94 ++++++++++ snapshot/system_snapshot.h | 3 + util/BUILD.gn | 14 +- util/ios/ios_system_data_collector.h | 81 +++++++++ util/ios/ios_system_data_collector.mm | 202 +++++++++++++++++++++ 13 files changed, 734 insertions(+), 14 deletions(-) create mode 100644 snapshot/ios/system_snapshot_ios.cc create mode 100644 snapshot/ios/system_snapshot_ios.h create mode 100644 util/ios/ios_system_data_collector.h create mode 100644 util/ios/ios_system_data_collector.mm diff --git a/client/BUILD.gn b/client/BUILD.gn index 476ceb2c..dfdb3351 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -44,7 +44,10 @@ static_library("client") { } if (crashpad_is_ios) { - sources += [ "crashpad_client_ios.cc" ] + sources += [ + "crash_report_database_mac.mm", + "crashpad_client_ios.cc", + ] } if (crashpad_is_linux || crashpad_is_android) { @@ -95,7 +98,10 @@ static_library("client") { # TODO(justincohen): Temporary dependency to bring up the iOS client. if (crashpad_is_ios) { - deps += [ "../snapshot" ] + deps += [ + "../minidump", + "../snapshot", + ] } if (crashpad_is_linux || crashpad_is_android) { diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index 8e3fafaa..9f63a916 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -20,6 +20,7 @@ #include "base/strings/stringprintf.h" #include "client/client_argv_handling.h" #include "snapshot/ios/process_snapshot_ios.h" +#include "util/ios/ios_system_data_collector.h" #include "util/posix/signals.h" namespace crashpad { @@ -43,7 +44,7 @@ class SignalHandler { void HandleCrash(int signo, siginfo_t* siginfo, void* context) { // TODO(justincohen): This is incomplete. ProcessSnapshotIOS process_snapshot; - process_snapshot.Initialize(); + process_snapshot.Initialize(system_data); } private: @@ -68,6 +69,9 @@ class SignalHandler { Signals::OldActions old_actions_ = {}; + // Collect some system data before the signal handler is triggered. + IOSSystemDataCollector system_data; + DISALLOW_COPY_AND_ASSIGN(SignalHandler); }; diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h index 9332f96e..97276d52 100644 --- a/minidump/minidump_extensions.h +++ b/minidump/minidump_extensions.h @@ -242,7 +242,7 @@ enum MinidumpOS : uint32_t { kMinidumpOSMacOSX = 0x8101, //! \brief iOS, Darwin for mobile devices. - kMinidumpOSiOS = 0x8102, + kMinidumpOSIOS = 0x8102, //! \brief Linux, not including Android. kMinidumpOSLinux = 0x8201, @@ -264,7 +264,6 @@ enum MinidumpOS : uint32_t { kMinidumpOSUnknown = 0xffffffff, }; - //! \brief A list of ::RVA pointers. struct ALIGNAS(4) PACKED MinidumpRVAList { //! \brief The number of children present in the #children array. diff --git a/minidump/minidump_system_info_writer.cc b/minidump/minidump_system_info_writer.cc index 06aeecda..7b4b49dc 100644 --- a/minidump/minidump_system_info_writer.cc +++ b/minidump/minidump_system_info_writer.cc @@ -176,6 +176,9 @@ void MinidumpSystemInfoWriter::InitializeFromSnapshot( case SystemSnapshot::kOperatingSystemFuchsia: operating_system = kMinidumpOSFuchsia; break; + case SystemSnapshot::kOperatingSystemIOS: + operating_system = kMinidumpOSIOS; + break; default: NOTREACHED(); operating_system = kMinidumpOSUnknown; diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 0a118d0f..8f67a00e 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -119,6 +119,8 @@ static_library("snapshot") { "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", diff --git a/snapshot/ios/process_snapshot_ios.cc b/snapshot/ios/process_snapshot_ios.cc index 27f9de4d..8decea70 100644 --- a/snapshot/ios/process_snapshot_ios.cc +++ b/snapshot/ios/process_snapshot_ios.cc @@ -17,15 +17,29 @@ #include <mach-o/loader.h> #include <mach/mach.h> -#include <utility> - #include "base/logging.h" #include "base/mac/mach_logging.h" +#include "base/stl_util.h" + +namespace { + +void MachTimeValueToTimeval(const time_value& mach, timeval* tv) { + tv->tv_sec = mach.seconds; + tv->tv_usec = mach.microseconds; +} + +} // namespace namespace crashpad { ProcessSnapshotIOS::ProcessSnapshotIOS() : ProcessSnapshot(), + kern_proc_info_(), + basic_info_user_time_(), + basic_info_system_time_(), + thread_times_user_time_(), + thread_times_system_time_(), + system_(), threads_(), modules_(), report_id_(), @@ -36,14 +50,50 @@ ProcessSnapshotIOS::ProcessSnapshotIOS() ProcessSnapshotIOS::~ProcessSnapshotIOS() {} -bool ProcessSnapshotIOS::Initialize() { +bool ProcessSnapshotIOS::Initialize(const IOSSystemDataCollector& system_data) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + // Used by pid, parent pid and snapshot time. + 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)) { + PLOG(ERROR) << "sysctl"; + return false; + } + + // Used by user time and system time. + task_basic_info_64 task_basic_info; + mach_msg_type_number_t task_basic_info_count = TASK_BASIC_INFO_64_COUNT; + kern_return_t kr = task_info(mach_task_self(), + TASK_BASIC_INFO_64, + reinterpret_cast<task_info_t>(&task_basic_info), + &task_basic_info_count); + if (kr != KERN_SUCCESS) { + MACH_LOG(WARNING, kr) << "task_info TASK_BASIC_INFO_64"; + return false; + } + + task_thread_times_info_data_t task_thread_times; + mach_msg_type_number_t task_thread_times_count = TASK_THREAD_TIMES_INFO_COUNT; + kr = task_info(mach_task_self(), + TASK_THREAD_TIMES_INFO, + reinterpret_cast<task_info_t>(&task_thread_times), + &task_thread_times_count); + if (kr != KERN_SUCCESS) { + MACH_LOG(WARNING, kr) << "task_info TASK_THREAD_TIMES"; + } + + basic_info_user_time_ = task_basic_info.user_time; + basic_info_system_time_ = task_basic_info.system_time; + thread_times_user_time_ = task_thread_times.user_time; + thread_times_system_time_ = task_thread_times.system_time; + if (gettimeofday(&snapshot_time_, nullptr) != 0) { PLOG(ERROR) << "gettimeofday"; return false; } + system_.Initialize(system_data); InitializeThreads(); InitializeModules(); @@ -53,12 +103,12 @@ bool ProcessSnapshotIOS::Initialize() { pid_t ProcessSnapshotIOS::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return getpid(); + return kern_proc_info_.kp_proc.p_pid; } pid_t ProcessSnapshotIOS::ParentProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return 0; + return kern_proc_info_.kp_eproc.e_ppid; } void ProcessSnapshotIOS::SnapshotTime(timeval* snapshot_time) const { @@ -68,11 +118,28 @@ void ProcessSnapshotIOS::SnapshotTime(timeval* snapshot_time) const { void ProcessSnapshotIOS::ProcessStartTime(timeval* start_time) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *start_time = kern_proc_info_.kp_proc.p_starttime; } void ProcessSnapshotIOS::ProcessCPUTimes(timeval* user_time, timeval* system_time) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + // Calculate user and system time the same way the kernel does for + // getrusage(). See 10.15.0 xnu-6153.11.26/bsd/kern/kern_resource.c calcru(). + timerclear(user_time); + timerclear(system_time); + + MachTimeValueToTimeval(basic_info_user_time_, user_time); + MachTimeValueToTimeval(basic_info_system_time_, system_time); + + timeval thread_user_time; + MachTimeValueToTimeval(thread_times_user_time_, &thread_user_time); + timeval thread_system_time; + MachTimeValueToTimeval(thread_times_system_time_, &thread_system_time); + + timeradd(user_time, &thread_user_time, user_time); + timeradd(system_time, &thread_system_time, system_time); } void ProcessSnapshotIOS::ReportID(UUID* report_id) const { @@ -93,7 +160,7 @@ ProcessSnapshotIOS::AnnotationsSimpleMap() const { const SystemSnapshot* ProcessSnapshotIOS::System() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return nullptr; + return &system_; } std::vector<const ThreadSnapshot*> ProcessSnapshotIOS::Threads() const { diff --git a/snapshot/ios/process_snapshot_ios.h b/snapshot/ios/process_snapshot_ios.h index 19d43b2e..28b67613 100644 --- a/snapshot/ios/process_snapshot_ios.h +++ b/snapshot/ios/process_snapshot_ios.h @@ -15,9 +15,12 @@ #ifndef CRASHPAD_SNAPSHOT_IOS_PROCESS_SNAPSHOT_IOS_H_ #define CRASHPAD_SNAPSHOT_IOS_PROCESS_SNAPSHOT_IOS_H_ +#include <sys/sysctl.h> + #include <vector> #include "snapshot/ios/module_snapshot_ios.h" +#include "snapshot/ios/system_snapshot_ios.h" #include "snapshot/ios/thread_snapshot_ios.h" #include "snapshot/process_snapshot.h" #include "snapshot/thread_snapshot.h" @@ -34,9 +37,25 @@ class ProcessSnapshotIOS final : public ProcessSnapshot { //! \brief Initializes the object. //! + //! \param[in] system_data A class containing various system data points. + //! //! \return `true` if the snapshot could be created, `false` otherwise with //! an appropriate message logged. - bool Initialize(); + bool Initialize(const IOSSystemDataCollector& system_data); + + //! \brief Sets the value to be returned by ClientID(). + //! + //! On iOS, the client ID is under the control of the snapshot producer, + //! which may call this method to set the client ID. If this is not done, + //! ClientID() will return an identifier consisting entirely of zeroes. + void SetClientID(const UUID& client_id) { client_id_ = client_id; } + + //! \brief Sets the value to be returned by ReportID(). + //! + //! On iOS, the crash report ID is under the control of the snapshot + //! producer, which may call this method to set the report ID. If this is not + //! done, ReportID() will return an identifier consisting entirely of zeroes. + void SetReportID(const UUID& report_id) { report_id_ = report_id; } // ProcessSnapshot: pid_t ProcessID() const override; @@ -65,6 +84,12 @@ class ProcessSnapshotIOS final : public ProcessSnapshot { // Initializes threads_ on behalf of Initialize(). void InitializeThreads(); + kinfo_proc kern_proc_info_; + time_value_t basic_info_user_time_; + time_value_t basic_info_system_time_; + time_value_t thread_times_user_time_; + time_value_t thread_times_system_time_; + internal::SystemSnapshotIOS system_; std::vector<std::unique_ptr<internal::ThreadSnapshotIOS>> threads_; std::vector<std::unique_ptr<internal::ModuleSnapshotIOS>> modules_; UUID report_id_; diff --git a/snapshot/ios/system_snapshot_ios.cc b/snapshot/ios/system_snapshot_ios.cc new file mode 100644 index 00000000..57c686e8 --- /dev/null +++ b/snapshot/ios/system_snapshot_ios.cc @@ -0,0 +1,224 @@ +// 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/ios/system_snapshot_ios.h" + +#include <mach/mach.h> +#include <stddef.h> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <sys/utsname.h> + +#include <algorithm> + +#include "base/logging.h" +#include "base/mac/mach_logging.h" +#include "base/strings/stringprintf.h" +#include "build/build_config.h" +#include "snapshot/cpu_context.h" +#include "snapshot/posix/timezone.h" +#include "util/mac/mac_util.h" +#include "util/numeric/in_range_cast.h" + +namespace crashpad { + +namespace internal { + +SystemSnapshotIOS::SystemSnapshotIOS() + : SystemSnapshot(), + os_version_build_(), + machine_description_(), + os_version_major_(0), + os_version_minor_(0), + os_version_bugfix_(0), + active_(0), + inactive_(0), + wired_(0), + free_(0), + cpu_count_(0), + cpu_vendor_(), + dst_status_(), + standard_offset_seconds_(0), + daylight_offset_seconds_(0), + standard_name_(), + daylight_name_(), + initialized_() {} + +SystemSnapshotIOS::~SystemSnapshotIOS() {} + +void SystemSnapshotIOS::Initialize(const IOSSystemDataCollector& system_data) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + system_data.OSVersion(&os_version_major_, + &os_version_minor_, + &os_version_bugfix_, + &os_version_build_); + machine_description_ = system_data.MachineDescription(); + cpu_count_ = system_data.ProcessorCount(); + cpu_vendor_ = system_data.CPUVendor(); + if (system_data.HasDaylightSavingTime()) { + dst_status_ = system_data.IsDaylightSavingTime() + ? SystemSnapshot::kObservingDaylightSavingTime + : SystemSnapshot::kObservingStandardTime; + } else { + dst_status_ = SystemSnapshot::kDoesNotObserveDaylightSavingTime; + } + standard_offset_seconds_ = system_data.StandardOffsetSeconds(); + daylight_offset_seconds_ = system_data.DaylightOffsetSeconds(); + standard_name_ = system_data.StandardName(); + daylight_name_ = system_data.DaylightName(); + + // Currently unused by minidump. + vm_size_t page_size; + host_page_size(mach_host_self(), &page_size); + mach_msg_type_number_t host_size = + sizeof(vm_statistics_data_t) / sizeof(integer_t); + vm_statistics_data_t vm_stat; + kern_return_t kr = host_statistics(mach_host_self(), + HOST_VM_INFO, + reinterpret_cast<host_info_t>(&vm_stat), + &host_size); + if (kr != KERN_SUCCESS) { + MACH_LOG(WARNING, kr) << "host_statistics"; + } + active_ = vm_stat.active_count * page_size; + inactive_ = vm_stat.inactive_count * page_size; + wired_ = vm_stat.wire_count * page_size; + free_ = vm_stat.free_count * page_size; + + INITIALIZATION_STATE_SET_VALID(initialized_); +} + +CPUArchitecture SystemSnapshotIOS::GetCPUArchitecture() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); +#if defined(ARCH_CPU_X86_64) + return kCPUArchitectureX86_64; +#elif defined(ARCH_CPU_ARM64) + return kCPUArchitectureARM64; +#endif +} + +uint32_t SystemSnapshotIOS::CPURevision() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // TODO(justincohen): sysctlbyname machdep.cpu.* returns -1 on iOS/ARM64, but + // consider recording this for X86_64 only. + return 0; +} + +uint8_t SystemSnapshotIOS::CPUCount() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return cpu_count_; +} + +std::string SystemSnapshotIOS::CPUVendor() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return cpu_vendor_; +} + +void SystemSnapshotIOS::CPUFrequency(uint64_t* current_hz, + uint64_t* max_hz) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // TODO(justincohen): sysctlbyname hw.cpufrequency returns -1 on iOS/ARM64, + // but consider recording this for X86_64 only. + *current_hz = 0; + *max_hz = 0; +} + +uint32_t SystemSnapshotIOS::CPUX86Signature() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // TODO(justincohen): Consider recording this for X86_64 only. + return 0; +} + +uint64_t SystemSnapshotIOS::CPUX86Features() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // TODO(justincohen): Consider recording this for X86_64 only. + return 0; +} + +uint64_t SystemSnapshotIOS::CPUX86ExtendedFeatures() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // TODO(justincohen): Consider recording this for X86_64 only. + return 0; +} + +uint32_t SystemSnapshotIOS::CPUX86Leaf7Features() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // TODO(justincohen): Consider recording this for X86_64 only. + return 0; +} + +bool SystemSnapshotIOS::CPUX86SupportsDAZ() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // TODO(justincohen): Consider recording this for X86_64 only. + return false; +} + +SystemSnapshot::OperatingSystem SystemSnapshotIOS::GetOperatingSystem() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return kOperatingSystemIOS; +} + +bool SystemSnapshotIOS::OSServer() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return false; +} + +void SystemSnapshotIOS::OSVersion(int* major, + int* minor, + int* bugfix, + std::string* build) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *major = os_version_major_; + *minor = os_version_minor_; + *bugfix = os_version_bugfix_; + build->assign(os_version_build_); +} + +std::string SystemSnapshotIOS::OSVersionFull() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return base::StringPrintf("%d.%d.%d %s", + os_version_major_, + os_version_minor_, + os_version_bugfix_, + os_version_build_.c_str()); +} + +std::string SystemSnapshotIOS::MachineDescription() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return machine_description_; +} + +bool SystemSnapshotIOS::NXEnabled() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + // TODO(justincohen): Consider using kern.nx when available (pre-iOS 13, + // pre-OS X 10.15). Otherwise the bit is always enabled. + return true; +} + +void SystemSnapshotIOS::TimeZone(DaylightSavingTimeStatus* dst_status, + int* standard_offset_seconds, + int* daylight_offset_seconds, + std::string* standard_name, + std::string* daylight_name) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + *dst_status = dst_status_; + *standard_offset_seconds = standard_offset_seconds_; + *daylight_offset_seconds = daylight_offset_seconds_; + standard_name->assign(standard_name_); + daylight_name->assign(daylight_name_); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/ios/system_snapshot_ios.h b/snapshot/ios/system_snapshot_ios.h new file mode 100644 index 00000000..a38de4ef --- /dev/null +++ b/snapshot/ios/system_snapshot_ios.h @@ -0,0 +1,94 @@ +// 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_IOS_SYSTEM_SNAPSHOT_IOS_H_ +#define CRASHPAD_SNAPSHOT_IOS_SYSTEM_SNAPSHOT_IOS_H_ + +#include <stdint.h> + +#include <string> + +#include "base/macros.h" +#include "snapshot/system_snapshot.h" +#include "util/ios/ios_system_data_collector.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { + +namespace internal { + +//! \brief A SystemSnapshot of the running system, when the system runs iOS. +class SystemSnapshotIOS final : public SystemSnapshot { + public: + SystemSnapshotIOS(); + ~SystemSnapshotIOS() override; + + //! \brief Initializes the object. + //! + //! \param[in] system_data A class containing various system data points. + void Initialize(const IOSSystemDataCollector& system_data); + + // SystemSnapshot: + + CPUArchitecture GetCPUArchitecture() const override; + uint32_t CPURevision() const override; + uint8_t CPUCount() const override; + std::string CPUVendor() const override; + void CPUFrequency(uint64_t* current_hz, uint64_t* max_hz) const override; + uint32_t CPUX86Signature() const override; + uint64_t CPUX86Features() const override; + uint64_t CPUX86ExtendedFeatures() const override; + uint32_t CPUX86Leaf7Features() const override; + bool CPUX86SupportsDAZ() const override; + OperatingSystem GetOperatingSystem() const override; + bool OSServer() const override; + void OSVersion(int* major, + int* minor, + int* bugfix, + std::string* build) const override; + std::string OSVersionFull() const override; + bool NXEnabled() const override; + std::string MachineDescription() const override; + void TimeZone(DaylightSavingTimeStatus* dst_status, + int* standard_offset_seconds, + int* daylight_offset_seconds, + std::string* standard_name, + std::string* daylight_name) const override; + + private: + std::string os_version_build_; + std::string machine_description_; + int os_version_major_; + int os_version_minor_; + int os_version_bugfix_; + uint64_t active_; + uint64_t inactive_; + uint64_t wired_; + uint64_t free_; + int cpu_count_; + std::string cpu_vendor_; + DaylightSavingTimeStatus dst_status_; + int standard_offset_seconds_; + int daylight_offset_seconds_; + std::string standard_name_; + std::string daylight_name_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(SystemSnapshotIOS); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_IOS_SYSTEM_SNAPSHOT_IOS_H_ diff --git a/snapshot/system_snapshot.h b/snapshot/system_snapshot.h index a363c0c8..d78cc235 100644 --- a/snapshot/system_snapshot.h +++ b/snapshot/system_snapshot.h @@ -50,6 +50,9 @@ class SystemSnapshot { //! \brief Fuchsia. kOperatingSystemFuchsia, + + //! \brief iOS. + kOperatingSystemIOS, }; //! \brief A system’s daylight saving time status. diff --git a/util/BUILD.gn b/util/BUILD.gn index bd0d2427..ab0fe359 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -17,6 +17,9 @@ import("net/tls.gni") if (crashpad_is_in_chromium) { import("//build/config/sanitizers/sanitizers.gni") + + # Prevent Chromium source assignment filters from being inherited. + set_sources_assignment_filter([]) } if (crashpad_is_mac) { @@ -241,6 +244,15 @@ static_library("util") { } } + if (crashpad_is_ios) { + sources += [ + "ios/ios_system_data_collector.h", + "ios/ios_system_data_collector.mm", + "mac/xattr.cc", + "mac/xattr.h", + ] + } + if (crashpad_is_mac) { sources += [ "mac/checked_mach_address_range.h", @@ -313,7 +325,6 @@ static_library("util") { } if (crashpad_is_linux || crashpad_is_android) { - set_sources_assignment_filter([]) sources += [ "linux/address_types.h", "linux/auxiliary_vector.cc", @@ -661,7 +672,6 @@ source_set("util_test") { } if (crashpad_is_linux || crashpad_is_android) { - set_sources_assignment_filter([]) sources += [ "linux/auxiliary_vector_test.cc", "linux/memory_map_test.cc", diff --git a/util/ios/ios_system_data_collector.h b/util/ios/ios_system_data_collector.h new file mode 100644 index 00000000..45837c66 --- /dev/null +++ b/util/ios/ios_system_data_collector.h @@ -0,0 +1,81 @@ +// 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_UTIL_IOS_IOS_SYSTEM_DATA_COLLECTOR_H_ +#define CRASHPAD_UTIL_IOS_IOS_SYSTEM_DATA_COLLECTOR_H_ + +#import <CoreFoundation/CoreFoundation.h> + +#include <string> + +namespace crashpad { + +//! \brief Used to collect system level data before a crash occurs. +class IOSSystemDataCollector { + public: + IOSSystemDataCollector(); + ~IOSSystemDataCollector(); + + void OSVersion(int* major, int* minor, int* bugfix, std::string* build) const; + std::string MachineDescription() const { return machine_description_; } + int ProcessorCount() const { return processor_count_; } + std::string CPUVendor() const { return cpu_vendor_; } + bool HasDaylightSavingTime() const { return has_next_daylight_saving_time_; } + bool IsDaylightSavingTime() const { return is_daylight_saving_time_; } + int StandardOffsetSeconds() const { return standard_offset_seconds_; } + int DaylightOffsetSeconds() const { return daylight_offset_seconds_; } + std::string StandardName() const { return standard_name_; } + std::string DaylightName() const { return daylight_name_; } + + // Currently unused by minidump. + int Orientation() const { return orientation_; } + + private: + // Notification handlers. + 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(); + + int major_version_; + int minor_version_; + int patch_version_; + std::string build_; + std::string machine_description_; + int orientation_; + int processor_count_; + std::string cpu_vendor_; + bool has_next_daylight_saving_time_; + bool is_daylight_saving_time_; + int standard_offset_seconds_; + int daylight_offset_seconds_; + std::string standard_name_; + std::string daylight_name_; +}; + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_IOS_IOS_SYSTEM_DATA_COLLECTOR_H_ diff --git a/util/ios/ios_system_data_collector.mm b/util/ios/ios_system_data_collector.mm new file mode 100644 index 00000000..ca6e91b8 --- /dev/null +++ b/util/ios/ios_system_data_collector.mm @@ -0,0 +1,202 @@ +// 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 "util/ios/ios_system_data_collector.h" + +#include <sys/sysctl.h> +#include <sys/utsname.h> + +#import <Foundation/Foundation.h> +#include <TargetConditionals.h> +#import <UIKit/UIKit.h> + +#include "base/mac/mach_logging.h" +#include "base/numerics/safe_conversions.h" +#include "build/build_config.h" + +namespace { + +std::string ReadStringSysctlByName(const char* name) { + size_t buf_len; + if (sysctlbyname(name, nullptr, &buf_len, nullptr, 0) != 0) { + PLOG(WARNING) << "sysctlbyname (size) " << name; + return std::string(); + } + + if (buf_len == 0) { + return std::string(); + } + + std::string value(buf_len - 1, '\0'); + if (sysctlbyname(name, &value[0], &buf_len, nullptr, 0) != 0) { + PLOG(WARNING) << "sysctlbyname " << name; + return std::string(); + } + + return value; +} + +} // namespace + +namespace crashpad { + +IOSSystemDataCollector::IOSSystemDataCollector() + : major_version_(0), + minor_version_(0), + patch_version_(0), + build_(), + machine_description_(), + orientation_(0), + processor_count_(0), + cpu_vendor_(), + has_next_daylight_saving_time_(false), + is_daylight_saving_time_(false), + standard_offset_seconds_(0), + daylight_offset_seconds_(0), + standard_name_(), + daylight_name_() { + NSOperatingSystemVersion version = + [[NSProcessInfo processInfo] operatingSystemVersion]; + major_version_ = base::saturated_cast<int>(version.majorVersion); + minor_version_ = base::saturated_cast<int>(version.minorVersion); + patch_version_ = base::saturated_cast<int>(version.patchVersion); + processor_count_ = + base::saturated_cast<int>([[NSProcessInfo processInfo] processorCount]); + build_ = ReadStringSysctlByName("kern.osversion"); + +#if defined(ARCH_CPU_X86_64) + cpu_vendor_ = ReadStringSysctlByName("machdep.cpu.vendor"); +#endif + +#if TARGET_OS_SIMULATOR + // TODO(justincohen): Consider adding board and model information to + // |machine_description| as well (similar to MacModelAndBoard in + // util/mac/mac_util.cc). + switch (UI_USER_INTERFACE_IDIOM()) { + case UIUserInterfaceIdiomPhone: + machine_description_ = "iOS Simulator (iPhone)"; + break; + case UIUserInterfaceIdiomPad: + machine_description_ = "iOS Simulator (iPad)"; + break; + default: + machine_description_ = "iOS Simulator (Unknown)"; + break; + } +#elif TARGET_OS_IPHONE + utsname uts; + if (uname(&uts) == 0) { + machine_description_ = uts.machine; + } +#else +#error "Unexpected target type OS." +#endif + + InstallHandlers(); +} + +IOSSystemDataCollector::~IOSSystemDataCollector() { + CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetLocalCenter(), + this); +} + +void IOSSystemDataCollector::OSVersion(int* major, + int* minor, + int* bugfix, + std::string* build) const { + *major = major_version_; + *minor = minor_version_; + *bugfix = patch_version_; + build->assign(build_); +} + +void IOSSystemDataCollector::InstallHandlers() { + // Timezone. + CFNotificationCenterAddObserver( + CFNotificationCenterGetLocalCenter(), + this, + IOSSystemDataCollector::SystemTimeZoneDidChangeNotificationHandler, + reinterpret_cast<CFStringRef>(NSSystemTimeZoneDidChangeNotification), + nullptr, + CFNotificationSuspensionBehaviorDeliverImmediately); + SystemTimeZoneDidChangeNotification(); + + // Orientation. + CFNotificationCenterAddObserver( + CFNotificationCenterGetLocalCenter(), + this, + IOSSystemDataCollector::OrientationDidChangeNotificationHandler, + reinterpret_cast<CFStringRef>(UIDeviceOrientationDidChangeNotification), + nullptr, + CFNotificationSuspensionBehaviorDeliverImmediately); + OrientationDidChangeNotification(); +} + +// static +void IOSSystemDataCollector::SystemTimeZoneDidChangeNotificationHandler( + CFNotificationCenterRef center, + void* observer, + CFStringRef name, + const void* object, + CFDictionaryRef userInfo) { + static_cast<IOSSystemDataCollector*>(observer) + ->SystemTimeZoneDidChangeNotification(); +} + +void IOSSystemDataCollector::SystemTimeZoneDidChangeNotification() { + NSTimeZone* time_zone = NSTimeZone.localTimeZone; + NSDate* transition = + [time_zone nextDaylightSavingTimeTransitionAfterDate:[NSDate date]]; + if (transition == nil) { + has_next_daylight_saving_time_ = false; + daylight_name_ = [[time_zone abbreviation] UTF8String]; + standard_name_ = daylight_name_; + } else if (time_zone.isDaylightSavingTime) { + has_next_daylight_saving_time_ = true; + is_daylight_saving_time_ = true; + daylight_offset_seconds_ = + base::saturated_cast<int>([time_zone secondsFromGMT]); + standard_offset_seconds_ = + base::saturated_cast<int>([time_zone secondsFromGMTForDate:transition]); + daylight_name_ = [[time_zone abbreviation] UTF8String]; + standard_name_ = [[time_zone abbreviationForDate:transition] UTF8String]; + } else { + has_next_daylight_saving_time_ = true; + is_daylight_saving_time_ = false; + standard_name_ = [[time_zone abbreviation] UTF8String]; + daylight_name_ = [[time_zone abbreviationForDate:transition] UTF8String]; + standard_offset_seconds_ = + base::saturated_cast<int>([time_zone secondsFromGMT]); + daylight_offset_seconds_ = + base::saturated_cast<int>([time_zone secondsFromGMTForDate:transition]); + } +} + +// static +void IOSSystemDataCollector::OrientationDidChangeNotificationHandler( + CFNotificationCenterRef center, + void* observer, + CFStringRef name, + const void* object, + CFDictionaryRef userInfo) { + static_cast<IOSSystemDataCollector*>(observer) + ->OrientationDidChangeNotification(); +} + +void IOSSystemDataCollector::OrientationDidChangeNotification() { + orientation_ = + base::saturated_cast<int>([[UIDevice currentDevice] orientation]); +} + +} // namespace crashpad From faae6470cf8900d7ab2f8ae27e0deba36009da1b Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Wed, 25 Mar 2020 16:13:42 -0400 Subject: [PATCH 360/401] [ios] Bring up first draft exceptions snapshot. Gather most of the necessary information for the exceptions snapshot. Note that: - The 'capture' portion of this CL will be moved out of the snapshot interface and into a separate in-process dump to disk location. - All of the pointer dereferences need to be wrapped in vm_read. - The read-fast-and-dump logic in thread_snapshot may end up in a different file completely, but until we pick a serialization/deserialization method, keep it as-is. Bug: crashpad:31 Change-Id: Iae4af436cddabd2302689b76c8a4574eb8e48c0e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2098744 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_ios.cc | 3 +- snapshot/BUILD.gn | 2 + snapshot/ios/exception_snapshot_ios.cc | 122 +++++++++++++++++++++++++ snapshot/ios/exception_snapshot_ios.h | 79 ++++++++++++++++ snapshot/ios/process_snapshot_ios.cc | 12 ++- snapshot/ios/process_snapshot_ios.h | 3 + 6 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 snapshot/ios/exception_snapshot_ios.cc create mode 100644 snapshot/ios/exception_snapshot_ios.h diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index 9f63a916..ba18947b 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -45,6 +45,8 @@ class SignalHandler { // TODO(justincohen): This is incomplete. ProcessSnapshotIOS process_snapshot; process_snapshot.Initialize(system_data); + process_snapshot.SetException(siginfo, + reinterpret_cast<ucontext_t*>(context)); } private: @@ -88,7 +90,6 @@ bool CrashpadClient::StartCrashpadInProcessHandler() { // static void CrashpadClient::DumpWithoutCrash() { DCHECK(SignalHandler::Get()); - siginfo_t siginfo = {}; SignalHandler::Get()->HandleCrash(siginfo.si_signo, &siginfo, nullptr); } diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 8f67a00e..3924c175 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -113,6 +113,8 @@ static_library("snapshot") { if (crashpad_is_ios) { sources += [ + "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", diff --git a/snapshot/ios/exception_snapshot_ios.cc b/snapshot/ios/exception_snapshot_ios.cc new file mode 100644 index 00000000..559b105e --- /dev/null +++ b/snapshot/ios/exception_snapshot_ios.cc @@ -0,0 +1,122 @@ +// 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/ios/exception_snapshot_ios.h" + +#include "base/logging.h" +#include "base/mac/mach_logging.h" +#include "base/strings/stringprintf.h" +#include "snapshot/cpu_context.h" +#include "snapshot/mac/cpu_context_mac.h" +#include "util/misc/from_pointer_cast.h" + +namespace crashpad { +namespace internal { + +ExceptionSnapshotIOS::ExceptionSnapshotIOS() + : ExceptionSnapshot(), + context_(), + codes_(), + thread_id_(0), + exception_address_(0), + signal_number_(0), + signal_code_(0), + initialized_() {} + +ExceptionSnapshotIOS::~ExceptionSnapshotIOS() {} + +bool ExceptionSnapshotIOS::Initialize(const siginfo_t* siginfo, + const ucontext_t* context) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + if (!context) + return false; + + mcontext_t mcontext = context->uc_mcontext; +#if defined(ARCH_CPU_X86_64) + context_.architecture = kCPUArchitectureX86_64; + context_.x86_64 = &context_x86_64_; + x86_debug_state64_t empty_debug_state; + InitializeCPUContextX86_64(&context_x86_64_, + THREAD_STATE_NONE, + nullptr, + 0, + &mcontext->__ss, + &mcontext->__fs, + &empty_debug_state); +#elif defined(ARCH_CPU_ARM64) + context_.architecture = kCPUArchitectureARM64; + context_.arm64 = &context_arm64_; + InitializeCPUContextARM64(&context_arm64_, &mcontext->__ss, &mcontext->__ns); +#endif + + // Thread ID. + thread_identifier_info identifier_info; + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + kern_return_t kr = + thread_info(mach_thread_self(), + THREAD_IDENTIFIER_INFO, + reinterpret_cast<thread_info_t>(&identifier_info), + &count); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "thread_identifier_info"; + } else { + thread_id_ = identifier_info.thread_id; + } + + signal_number_ = siginfo->si_signo; + signal_code_ = siginfo->si_code; + exception_address_ = FromPointerCast<uintptr_t>(siginfo->si_addr); + + INITIALIZATION_STATE_SET_VALID(initialized_); + return true; +} + +const CPUContext* ExceptionSnapshotIOS::Context() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return &context_; +} + +uint64_t ExceptionSnapshotIOS::ThreadID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return thread_id_; +} + +uint32_t ExceptionSnapshotIOS::Exception() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return signal_number_; +} + +uint32_t ExceptionSnapshotIOS::ExceptionInfo() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return signal_code_; +} + +uint64_t ExceptionSnapshotIOS::ExceptionAddress() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return exception_address_; +} + +const std::vector<uint64_t>& ExceptionSnapshotIOS::Codes() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return codes_; +} + +std::vector<const MemorySnapshot*> ExceptionSnapshotIOS::ExtraMemory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector<const MemorySnapshot*>(); +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/ios/exception_snapshot_ios.h b/snapshot/ios/exception_snapshot_ios.h new file mode 100644 index 00000000..3c19a074 --- /dev/null +++ b/snapshot/ios/exception_snapshot_ios.h @@ -0,0 +1,79 @@ +// 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_IOS_EXCEPTION_SNAPSHOT_IOS_H_ +#define CRASHPAD_SNAPSHOT_IOS_EXCEPTION_SNAPSHOT_IOS_H_ + +#include <mach/mach.h> +#include <stdint.h> + +#include <vector> + +#include "base/macros.h" +#include "build/build_config.h" +#include "snapshot/cpu_context.h" +#include "snapshot/exception_snapshot.h" +#include "util/mach/mach_extensions.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { + +namespace internal { + +//! \brief An ExceptionSnapshot of an exception sustained by a running (or +//! crashed) process on an iOS system. +class ExceptionSnapshotIOS final : public ExceptionSnapshot { + public: + ExceptionSnapshotIOS(); + ~ExceptionSnapshotIOS() override; + + //! \brief Initializes the object. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! an appropriate message logged. + bool Initialize(const siginfo_t* siginfo, const ucontext_t* context); + + // ExceptionSnapshot: + + const CPUContext* Context() const override; + uint64_t ThreadID() const override; + uint32_t Exception() const override; + uint32_t ExceptionInfo() const override; + uint64_t ExceptionAddress() const override; + const std::vector<uint64_t>& Codes() const override; + virtual std::vector<const MemorySnapshot*> ExtraMemory() const override; + + private: +#if defined(ARCH_CPU_X86_64) + CPUContextX86_64 context_x86_64_; +#elif defined(ARCH_CPU_ARM64) + CPUContextARM64 context_arm64_; +#else +#error Port. +#endif // ARCH_CPU_X86_64 + CPUContext context_; + std::vector<uint64_t> codes_; + uint64_t thread_id_; + uintptr_t exception_address_; + int signal_number_; + int signal_code_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ExceptionSnapshotIOS); +}; + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_IOS_EXCEPTION_SNAPSHOT_IOS_H_ diff --git a/snapshot/ios/process_snapshot_ios.cc b/snapshot/ios/process_snapshot_ios.cc index 8decea70..29701994 100644 --- a/snapshot/ios/process_snapshot_ios.cc +++ b/snapshot/ios/process_snapshot_ios.cc @@ -42,6 +42,7 @@ ProcessSnapshotIOS::ProcessSnapshotIOS() system_(), threads_(), modules_(), + exception_(), report_id_(), client_id_(), annotations_simple_map_(), @@ -101,6 +102,15 @@ bool ProcessSnapshotIOS::Initialize(const IOSSystemDataCollector& system_data) { return true; } +void ProcessSnapshotIOS::SetException(const siginfo_t* siginfo, + const ucontext_t* context) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + exception_.reset(new internal::ExceptionSnapshotIOS()); + if (!exception_->Initialize(siginfo, context)) { + exception_.reset(); + } +} + pid_t ProcessSnapshotIOS::ProcessID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return kern_proc_info_.kp_proc.p_pid; @@ -189,7 +199,7 @@ std::vector<UnloadedModuleSnapshot> ProcessSnapshotIOS::UnloadedModules() const ExceptionSnapshot* ProcessSnapshotIOS::Exception() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return nullptr; + return exception_.get(); } std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotIOS::MemoryMap() diff --git a/snapshot/ios/process_snapshot_ios.h b/snapshot/ios/process_snapshot_ios.h index 28b67613..2332ff45 100644 --- a/snapshot/ios/process_snapshot_ios.h +++ b/snapshot/ios/process_snapshot_ios.h @@ -19,6 +19,7 @@ #include <vector> +#include "snapshot/ios/exception_snapshot_ios.h" #include "snapshot/ios/module_snapshot_ios.h" #include "snapshot/ios/system_snapshot_ios.h" #include "snapshot/ios/thread_snapshot_ios.h" @@ -43,6 +44,7 @@ class ProcessSnapshotIOS final : public ProcessSnapshot { //! an appropriate message logged. bool Initialize(const IOSSystemDataCollector& system_data); + void SetException(const siginfo_t* siginfo, const ucontext_t* context); //! \brief Sets the value to be returned by ClientID(). //! //! On iOS, the client ID is under the control of the snapshot producer, @@ -92,6 +94,7 @@ class ProcessSnapshotIOS final : public ProcessSnapshot { internal::SystemSnapshotIOS system_; std::vector<std::unique_ptr<internal::ThreadSnapshotIOS>> threads_; std::vector<std::unique_ptr<internal::ModuleSnapshotIOS>> modules_; + std::unique_ptr<internal::ExceptionSnapshotIOS> exception_; UUID report_id_; UUID client_id_; std::map<std::string, std::string> annotations_simple_map_; From d3859d91fde093241143fec09caae6b5866ecd62 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 25 Mar 2020 19:31:09 -0400 Subject: [PATCH 361/401] mac: kern.nx is not present in 10.14.4 et seq, but NX is always enabled Bug: crashpad:295 Change-Id: Id1de68d402d229b43fab5e8d15b0fe23c618ce08 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2119645 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Justin Cohen <justincohen@chromium.org> --- snapshot/mac/system_snapshot_mac.cc | 41 ++++++++++++++++++++++-- snapshot/mac/system_snapshot_mac_test.cc | 6 ++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/snapshot/mac/system_snapshot_mac.cc b/snapshot/mac/system_snapshot_mac.cc index 21f254ee..1ece8166 100644 --- a/snapshot/mac/system_snapshot_mac.cc +++ b/snapshot/mac/system_snapshot_mac.cc @@ -14,6 +14,7 @@ #include "snapshot/mac/system_snapshot_mac.h" +#include <AvailabilityMacros.h> #include <stddef.h> #include <sys/sysctl.h> #include <sys/types.h> @@ -22,6 +23,7 @@ #include <algorithm> #include "base/logging.h" +#include "base/scoped_clear_errno.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "snapshot/cpu_context.h" @@ -34,11 +36,16 @@ namespace crashpad { namespace { +template <typename T> +int ReadIntSysctlByName_NoLog(const char* name, T* value) { + size_t value_len = sizeof(*value); + return sysctlbyname(name, value, &value_len, nullptr, 0); +} + template <typename T> T ReadIntSysctlByName(const char* name, T default_value) { T value; - size_t value_len = sizeof(value); - if (sysctlbyname(name, &value, &value_len, nullptr, 0) != 0) { + if (ReadIntSysctlByName_NoLog(name, &value) != 0) { PLOG(WARNING) << "sysctlbyname " << name; return default_value; } @@ -338,7 +345,35 @@ std::string SystemSnapshotMac::MachineDescription() const { bool SystemSnapshotMac::NXEnabled() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return ReadIntSysctlByName<int>("kern.nx", 0); + + int value; + if (ReadIntSysctlByName_NoLog("kern.nx", &value) != 0) { + { + // Support for the kern.nx sysctlbyname is compiled out of production + // kernels on macOS 10.14.4 and later, although it’s available in + // development and debug kernels. Compare 10.14.3 + // xnu-4903.241.1/bsd/kern/kern_sysctl.c to 10.15.0 + // xnu-6153.11.26/bsd/kern/kern_sysctl.c (10.14.4 xnu source is not yet + // available). In newer production kernels, NX is always enabled. See + // 10.15.0 xnu-6153.11.26/osfmk/x86_64/pmap.c nx_enabled. +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 + const bool nx_always_enabled = true; +#else // DT >= 10.14 + base::ScopedClearErrno reset_errno; + const bool nx_always_enabled = MacOSXMinorVersion() >= 14; +#endif // DT >= 10.14 + if (nx_always_enabled) { + return true; + } + } + + // Even if sysctlbyname should have worked, NX is enabled by default in all + // supported configurations, so return true even while warning. + PLOG(WARNING) << "sysctlbyname kern.nx"; + return true; + } + + return value; } void SystemSnapshotMac::TimeZone(DaylightSavingTimeStatus* dst_status, diff --git a/snapshot/mac/system_snapshot_mac_test.cc b/snapshot/mac/system_snapshot_mac_test.cc index 69048eb0..2b665924 100644 --- a/snapshot/mac/system_snapshot_mac_test.cc +++ b/snapshot/mac/system_snapshot_mac_test.cc @@ -126,6 +126,12 @@ TEST_F(SystemSnapshotMacTest, MachineDescription) { EXPECT_FALSE(system_snapshot().MachineDescription().empty()); } +TEST_F(SystemSnapshotMacTest, NXEnabled) { + // Assume NX will always be enabled, as it was always enabled by default on + // all supported versions of macOS. + EXPECT_TRUE(system_snapshot().NXEnabled()); +} + } // namespace } // namespace test } // namespace crashpad From af62d7fcf61da5a8a6bb9336f0b5ee22547d36a7 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Wed, 25 Mar 2020 23:02:52 -0400 Subject: [PATCH 362/401] Correct use of -[NSString UTF8String]. Fixes the chromium presubmit error for UTF8String: The use of -[NSString UTF8String] is dangerous as it can return null even if |canBeConvertedToEncoding:NSUTF8StringEncoding| returns YES. Please use |SysNSStringToUTF8| instead. Bug: crashpad:31 Change-Id: Iaf939012ea9d342f6a01af58119cef962319aefe Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2119613 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- util/ios/ios_system_data_collector.mm | 39 ++++++++++++++++----------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/util/ios/ios_system_data_collector.mm b/util/ios/ios_system_data_collector.mm index ca6e91b8..c81fe3f8 100644 --- a/util/ios/ios_system_data_collector.mm +++ b/util/ios/ios_system_data_collector.mm @@ -23,6 +23,7 @@ #include "base/mac/mach_logging.h" #include "base/numerics/safe_conversions.h" +#include "base/strings/sys_string_conversions.h" #include "build/build_config.h" namespace { @@ -160,26 +161,32 @@ void IOSSystemDataCollector::SystemTimeZoneDidChangeNotification() { [time_zone nextDaylightSavingTimeTransitionAfterDate:[NSDate date]]; if (transition == nil) { has_next_daylight_saving_time_ = false; - daylight_name_ = [[time_zone abbreviation] UTF8String]; - standard_name_ = daylight_name_; - } else if (time_zone.isDaylightSavingTime) { - has_next_daylight_saving_time_ = true; - is_daylight_saving_time_ = true; - daylight_offset_seconds_ = - base::saturated_cast<int>([time_zone secondsFromGMT]); + is_daylight_saving_time_ = false; standard_offset_seconds_ = base::saturated_cast<int>([time_zone secondsFromGMTForDate:transition]); - daylight_name_ = [[time_zone abbreviation] UTF8String]; - standard_name_ = [[time_zone abbreviationForDate:transition] UTF8String]; + standard_name_ = base::SysNSStringToUTF8([time_zone abbreviation]); + daylight_offset_seconds_ = standard_offset_seconds_; + daylight_name_ = standard_name_; } else { has_next_daylight_saving_time_ = true; - is_daylight_saving_time_ = false; - standard_name_ = [[time_zone abbreviation] UTF8String]; - daylight_name_ = [[time_zone abbreviationForDate:transition] UTF8String]; - standard_offset_seconds_ = - base::saturated_cast<int>([time_zone secondsFromGMT]); - daylight_offset_seconds_ = - base::saturated_cast<int>([time_zone secondsFromGMTForDate:transition]); + is_daylight_saving_time_ = time_zone.isDaylightSavingTime; + if (time_zone.isDaylightSavingTime) { + standard_offset_seconds_ = base::saturated_cast<int>( + [time_zone secondsFromGMTForDate:transition]); + standard_name_ = + base::SysNSStringToUTF8([time_zone abbreviationForDate:transition]); + daylight_offset_seconds_ = + base::saturated_cast<int>([time_zone secondsFromGMT]); + daylight_name_ = base::SysNSStringToUTF8([time_zone abbreviation]); + } else { + standard_offset_seconds_ = + base::saturated_cast<int>([time_zone secondsFromGMT]); + standard_name_ = base::SysNSStringToUTF8([time_zone abbreviation]); + daylight_offset_seconds_ = base::saturated_cast<int>( + [time_zone secondsFromGMTForDate:transition]); + daylight_name_ = + base::SysNSStringToUTF8([time_zone abbreviationForDate:transition]); + } } } From 61a4f3d7d6f65945e81aaffe701da75c60c3ff2d Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 30 Mar 2020 11:48:38 -0400 Subject: [PATCH 363/401] mac: kern.nx is not present in 10.14.5 et seq, but NX is always enabled This updates the comment from d3859d91fde0, which referred to 10.14.4 as the OS version where kern.nx stoppoed working. Testing indicates that kern.nx works in 10.13.6 17G12034 and 10.14.4 18E226. It does not work in 10.14.5 18F132 or 10.15.4 19E266. Bug: crashpad:295 Change-Id: Id2f222700fb626de707d60980fedbd79e62990e6 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2127566 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- snapshot/mac/system_snapshot_mac.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/snapshot/mac/system_snapshot_mac.cc b/snapshot/mac/system_snapshot_mac.cc index 1ece8166..586aabea 100644 --- a/snapshot/mac/system_snapshot_mac.cc +++ b/snapshot/mac/system_snapshot_mac.cc @@ -350,12 +350,12 @@ bool SystemSnapshotMac::NXEnabled() const { if (ReadIntSysctlByName_NoLog("kern.nx", &value) != 0) { { // Support for the kern.nx sysctlbyname is compiled out of production - // kernels on macOS 10.14.4 and later, although it’s available in + // kernels on macOS 10.14.5 and later, although it’s available in // development and debug kernels. Compare 10.14.3 // xnu-4903.241.1/bsd/kern/kern_sysctl.c to 10.15.0 - // xnu-6153.11.26/bsd/kern/kern_sysctl.c (10.14.4 xnu source is not yet - // available). In newer production kernels, NX is always enabled. See - // 10.15.0 xnu-6153.11.26/osfmk/x86_64/pmap.c nx_enabled. + // xnu-6153.11.26/bsd/kern/kern_sysctl.c (10.14.4 and 10.14.5 xnu source + // are not yet available). In newer production kernels, NX is always + // enabled. See 10.15.0 xnu-6153.11.26/osfmk/x86_64/pmap.c nx_enabled. #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 const bool nx_always_enabled = true; #else // DT >= 10.14 From e39aacbd66c7288886af621ff00c2a2edb08a043 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Wed, 1 Apr 2020 13:58:01 -0400 Subject: [PATCH 364/401] Roll crashpad/third_party/mini_chromium/mini_chromium/ c426ff98e..731e08f06 (1 commit) https://chromium.googlesource.com/chromium/mini_chromium/+log/c426ff98e1d9..731e08f06958 $ git log c426ff98e..731e08f06 --date=short --no-merges --format='%ad %ae %s' 2020-03-31 justincohen Strip arm64e from XCTRunner if present. Created with: roll-dep crashpad/third_party/mini_chromium/mini_chromium Change-Id: Ic682d6c98e313eaf56e58ef1eb90a65b48775f1d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2132727 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 8b958f18..43334df2 100644 --- a/DEPS +++ b/DEPS @@ -42,7 +42,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'c426ff98e1d9e9d59777fe8b883a5c0ceeca9ca3', + '731e08f0695801347a26d2b204d5c18f51c98282', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', From 194e23910c13a68097f7dc7d058fdecd5ebd0b08 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 1 Apr 2020 17:03:20 -0400 Subject: [PATCH 365/401] Change for loops to use const references where they did not previously From cl/304219049: Optimize C++11 range-based for loops where the variable is copied in each iteration but it would suffice to obtain it by const reference. This is only applied to loop variables of types that are expensive to copy which means they are not trivially copyable or have a non-trivial copy constructor or destructor. To ensure that it is safe to replace the copy with a const reference, the following heuristic is employed: - The loop variable is const qualified. - The loop variable is not const, but only const methods or operators are invoked on it, or it is used as const reference or value argument in constructors or function calls. Change-Id: I5755eb523f60744079b0eb50424395079dcb0f02 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2132844 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- handler/minidump_to_upload_parameters.cc | 2 +- minidump/minidump_unloaded_module_writer.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/handler/minidump_to_upload_parameters.cc b/handler/minidump_to_upload_parameters.cc index 9e26d877..6b64081e 100644 --- a/handler/minidump_to_upload_parameters.cc +++ b/handler/minidump_to_upload_parameters.cc @@ -50,7 +50,7 @@ std::map<std::string, std::string> BreakpadHTTPFormParametersFromMinidump( } } - for (std::string annotation : module->AnnotationsVector()) { + for (const std::string& annotation : module->AnnotationsVector()) { list_annotations.append(annotation); list_annotations.append("\n"); } diff --git a/minidump/minidump_unloaded_module_writer.cc b/minidump/minidump_unloaded_module_writer.cc index 855e1967..c8a5f0fd 100644 --- a/minidump/minidump_unloaded_module_writer.cc +++ b/minidump/minidump_unloaded_module_writer.cc @@ -123,7 +123,8 @@ void MinidumpUnloadedModuleListWriter::InitializeFromSnapshot( DCHECK_EQ(state(), kStateMutable); DCHECK(unloaded_modules_.empty()); - for (auto unloaded_module_snapshot : unloaded_module_snapshots) { + for (const UnloadedModuleSnapshot& unloaded_module_snapshot : + unloaded_module_snapshots) { auto unloaded_module = std::make_unique<MinidumpUnloadedModuleWriter>(); unloaded_module->InitializeFromSnapshot(unloaded_module_snapshot); AddUnloadedModule(std::move(unloaded_module)); From 9da2573ca993fd1d958376c7a9f546f83cee6959 Mon Sep 17 00:00:00 2001 From: Sukumar Mokkarala <venkatasaisukumar222@gmail.com> Date: Thu, 2 Apr 2020 11:54:32 +0530 Subject: [PATCH 366/401] linux: Patch for capget syscall error Bug: crashpad:332 Change-Id: If867fd1780e4be1567048ad7fab29f5e61560aff Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2120780 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- handler/linux/exception_handler_server.cc | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index 7bb14f92..c9fbb0ad 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -93,23 +93,20 @@ PtraceScope GetPtraceScope() { } bool HaveCapSysPtrace() { - struct __user_cap_header_struct cap_header = {}; - struct __user_cap_data_struct cap_data = {}; - + __user_cap_header_struct cap_header; cap_header.pid = getpid(); + cap_header.version = _LINUX_CAPABILITY_VERSION_3; + __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3]; if (syscall(SYS_capget, &cap_header, &cap_data) != 0) { PLOG(ERROR) << "capget"; + LOG_IF(ERROR, errno == EINVAL) << "cap_header.version " << std::hex + << cap_header.version; return false; } - if (cap_header.version != _LINUX_CAPABILITY_VERSION_3) { - LOG(ERROR) << "Unexpected capability version " << std::hex - << cap_header.version; - return false; - } - - return (cap_data.effective & (1 << CAP_SYS_PTRACE)) != 0; + return (cap_data[CAP_TO_INDEX(CAP_SYS_PTRACE)].effective & + CAP_TO_MASK(CAP_SYS_PTRACE)) != 0; } bool SendMessageToClient( From c4cc4e6ac92d2c5c262d352f0435220db42334f8 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Wed, 8 Apr 2020 09:56:20 -0700 Subject: [PATCH 367/401] android: initialize signal dispositions Bionic installs signal handlers which request crash dumps from Android's debuggerd, but there are errors in how signals which aren't automatically re-raised are handled on Marshmallow (API 23). Before requesting a dump, Bionic acquires a lock to communicate with debuggerd and expecting imminent death, never releases it. While handling the dump request, debuggerd allows the dying process to continue before ptrace-detaching it. So, when Bionic manually re-raises a signal, it is intercepted by debuggerd and the dying process is allowed to live. Bionic restores SIG_DFL for the signal it's just handled, but if a different crash signal is later recieved, Bionic attempts to reacquire the lock to communicate with debuggerd and blocks forever. Disable Bionic's signal handlers for these signals on Marshmallow. Bug: chromium:1050178 Change-Id: Ia1fc5a24161a95931684d092ba8fee2f0dfbbdbb Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2134513 Reviewed-by: Mark Mentovai <mark@chromium.org> --- test/BUILD.gn | 6 ++ test/gtest_main.cc | 8 +++ util/BUILD.gn | 7 ++ util/linux/initial_signal_dispositions.cc | 78 +++++++++++++++++++++++ util/linux/initial_signal_dispositions.h | 41 ++++++++++++ util/util.gyp | 2 + 6 files changed, 142 insertions(+) create mode 100644 util/linux/initial_signal_dispositions.cc create mode 100644 util/linux/initial_signal_dispositions.h diff --git a/test/BUILD.gn b/test/BUILD.gn index a00f682f..bfbdd513 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -245,6 +245,9 @@ static_library("gmock_main") { "../third_party/mini_chromium:base", "../third_party/mini_chromium:base_test_support", ] + if (crashpad_is_android) { + deps += [ "../util" ] + } if (crashpad_is_ios) { deps += [ "ios:google_test_setup" ] } @@ -261,6 +264,9 @@ static_library("gtest_main") { "../third_party/mini_chromium:base", "../third_party/mini_chromium:base_test_support", ] + if (crashpad_is_android) { + deps += [ "../util" ] + } if (crashpad_is_ios) { deps += [ "ios:google_test_setup" ] } diff --git a/test/gtest_main.cc b/test/gtest_main.cc index ad3a095e..73cdddfa 100644 --- a/test/gtest_main.cc +++ b/test/gtest_main.cc @@ -21,6 +21,10 @@ #include "gmock/gmock.h" #endif // CRASHPAD_TEST_LAUNCHER_GMOCK +#if defined(OS_ANDROID) +#include "util/linux/initial_signal_dispositions.h" +#endif // OS_ANDROID + #if defined(OS_IOS) #include "test/ios/google_test_setup.h" #endif @@ -55,6 +59,10 @@ bool GetChildTestFunctionName(std::string* child_func_name) { } // namespace int main(int argc, char* argv[]) { +#if defined(OS_ANDROID) + crashpad::InitializeSignalDispositions(); +#endif // OS_ANDROID + crashpad::test::InitializeMainArguments(argc, argv); #if !defined(OS_IOS) diff --git a/util/BUILD.gn b/util/BUILD.gn index ab0fe359..43b248e1 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -324,6 +324,13 @@ static_library("util") { } } + if (crashpad_is_android) { + sources += [ + "linux/initial_signal_dispositions.cc", + "linux/initial_signal_dispositions.h", + ] + } + if (crashpad_is_linux || crashpad_is_android) { sources += [ "linux/address_types.h", diff --git a/util/linux/initial_signal_dispositions.cc b/util/linux/initial_signal_dispositions.cc new file mode 100644 index 00000000..b72b2476 --- /dev/null +++ b/util/linux/initial_signal_dispositions.cc @@ -0,0 +1,78 @@ +// 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 "util/linux/initial_signal_dispositions.h" + +#include <android/api-level.h> +#include <signal.h> + +#include "base/logging.h" +#include "build/build_config.h" + +#if __ANDROID_API__ <= 23 + +namespace crashpad { +namespace { +bool LoggingSignal(int signum, sighandler_t handler) { + sighandler_t previous = signal(signum, handler); + PLOG_IF(ERROR, previous == SIG_ERR) << "signal " << signum; + return previous != SIG_ERR; +} +} // namespace + +#endif // __ANDROID_API__ <= 23 + +bool InitializeSignalDispositions() { +#if __ANDROID_API__ <= 23 + const int api_level = android_get_device_api_level(); + if (api_level < 0) { + LOG(WARNING) << "bad api level"; + return false; + } + + // Bionic installs signal handlers which request crash dumps from Android's + // debuggerd, but there are errors in how signals which aren't automatically + // re-raised are handled on Marshmallow (API 23). + // + // Before requesting a dump, Bionic acquires a lock to communicate with + // debuggerd and expecting imminent death, never releases it. + // + // While handling the dump request, debuggerd allows the dying process to + // continue before ptrace-detaching it. So, when Bionic manually re-raises a + // signal, it is intercepted by debuggerd and the dying process is allowed to + // live. + // + // Bionic restores SIG_DFL for the signal it's just handled, but if a + // different crash signal is later recieved, Bionic attempts to reacquire the + // lock to communicate with debuggerd and blocks forever. + // + // Disable Bionic's signal handlers for these signals on Marshmallow. + bool success = true; + if (api_level == 23) { + success = LoggingSignal(SIGABRT, SIG_DFL); + success = LoggingSignal(SIGFPE, SIG_DFL) && success; + success = LoggingSignal(SIGPIPE, SIG_DFL) && success; +#if defined(SIGSTKFLT) + success = LoggingSignal(SIGSTKFLT, SIG_DFL) && success; +#endif + success = LoggingSignal(SIGTRAP, SIG_DFL) && success; + } + + return success; +#else + return true; +#endif // __ANDROID_API__ <= 23 +} + +} // namespace crashpad diff --git a/util/linux/initial_signal_dispositions.h b/util/linux/initial_signal_dispositions.h new file mode 100644 index 00000000..b67083c7 --- /dev/null +++ b/util/linux/initial_signal_dispositions.h @@ -0,0 +1,41 @@ +// 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_UTIL_LINUX_INITIAL_SIGNAL_DISPOSITIONS_H +#define CRASHPAD_UTIL_LINUX_INITIAL_SIGNAL_DISPOSITIONS_H + +namespace crashpad { + +//! \brief Establishes signal dispositions for a process based on the platform. +//! +//! Default signal dispositions are normally configured by the kernel, but +//! additional signal handlers might be installed by dependent or preloaded +//! libraries, e.g. Bionic normally installs signal handlers which log stack +//! traces to Android's logcat. +//! +//! This function initializes signal dispositions when the default dispositions +//! provided by the platform are broken. This function must be called before any +//! application level signal handlers have been installed and should be called +//! early in the process lifetime to reduce the chance of any broken signal +//! handlers being triggered. +//! +//! When running on Android M (API 23), this function installs `SIG_DFL` for +//! signals: `SIGABRT`, `SIGFPE`, `SIGPIPE`, `SIGSTKFLT`, and `SIGTRAP`. +//! +//! \return `true` on success. Otherwise `false` with a message logged. +bool InitializeSignalDispositions(); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_LINUX_INITIAL_SIGNAL_DISPOSITIONS_H diff --git a/util/util.gyp b/util/util.gyp index 3c980e4e..78a432a1 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -67,6 +67,8 @@ 'linux/exception_handler_protocol.cc', 'linux/exception_handler_protocol.h', 'linux/exception_information.h', + 'linux/initial_signal_dispositions.cc', + 'linux/initial_signal_dispositions.h', 'linux/memory_map.cc', 'linux/memory_map.h', 'linux/proc_stat_reader.cc', From de5bc33b8b45b197977430a0e74a37c00c6a3bc3 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Wed, 8 Apr 2020 13:19:46 -0700 Subject: [PATCH 368/401] fuchsia: Include reference to zx library "library zx" used to be built in to fidlc, but is now a standalone file (this is an SDK change). Update the build rules to adapt to this. ref: https://logs.chromium.org/logs/crashpad/buildbucket/cr-buildbucket.appspot.com/8883567878548782112/+/steps/compile_with_ninja/0/stdout FAILED: gen/fidl/include/fuchsia/sysinfo/c/client.cc gen/fidl/include/fuchsia/sysinfo/c/fidl.h gen/third_party/fuchsia/fidl/fuchsia.sysinfo/tables.c gen/third_party/fuchsia/fidl/fuchsia.sysinfo/intermediary_representation.json python ../../third_party/fuchsia/runner.py ../../third_party/fuchsia/sdk/linux-amd64/tools/fidlc --c-header gen/fidl/include/fuchsia/sysinfo/c/fidl.h --c-client gen/fidl/include/fuchsia/sysinfo/c/client.cc --tables gen/third_party/fuchsia/fidl/fuchsia.sysinfo/tables.c --json gen/third_party/fuchsia/fidl/fuchsia.sysinfo/intermediary_representation.json --name fuchsia.sysinfo --files ../../third_party/fuchsia/sdk/linux-amd64/fidl/fuchsia.sysinfo/sysinfo.fidl ../../third_party/fuchsia/sdk/linux-amd64/fidl/fuchsia.sysinfo/sysinfo.fidl:7:7: error: Could not find library named zx. Did you include its sources with --files? using zx; ^~ Bug: fuchsia:7802 Change-Id: I10c0109fd9621a19d72deb21a489c2041caeeeca Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2141019 Commit-Queue: Scott Graham <scottmg@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Justin Cohen <justincohen@chromium.org> --- third_party/fuchsia/BUILD.gn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 4111c582..71a648eb 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -156,6 +156,8 @@ if (crashpad_is_in_fuchsia) { "--name", fidl_source.library_name, "--files", + rebase_path("$sdk_fidl_sources_path/zx/zx_common.fidl", root_build_dir), + "--files", rebase_path(fidl_source.fidl, root_build_dir), ] From b2fd7d5307b083613469c29c09c5710265f47a91 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Wed, 8 Apr 2020 15:37:55 -0400 Subject: [PATCH 369/401] [ios] Bring up first half of UncaughtExceptionHandler. When code raises an Objective-C exception, unwind the stack looking for any exception handlers. If an exception handler is encountered, test to see if it is a function known to be a catch-and-rethrow 'sinkhole' exception handler. Various routines in UIKit and elsewhere do this, and they obscure the exception stack, since the original throw location is no longer present on the stack (just the re-throw) when Crashpad captures the crash report. In the case of sinkholes, trigger an immediate exception to capture the original stack. The is an improvement over the alternative, NSSetUncaughtExceptionHandler, which passes along the stack frames, but not the stack memory contents and full exception context itself. The details of what happens after a fatal exception is triggered are unresolved in this CL. For now, simply call std::terminate. This code was inspired by chromium/src/chrome/browser/mac/ exception_processor.mm. Bug: crashpad:31 Change-Id: Ieebc6476a0507c466c8219c10f790ec0a624e58c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2125254 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Robert Sesek <rsesek@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/BUILD.gn | 2 +- client/crashpad_client_ios.cc | 4 +- client/crashpad_client_ios_test.cc | 32 --- client/crashpad_client_ios_test.mm | 56 +++++ test/ios/crash_type_xctest.mm | 78 +++++++ test/ios/host/application_delegate.mm | 38 ++++ test/ios/host/cptest_shared_object.h | 15 ++ util/BUILD.gn | 2 + util/ios/exception_processor.h | 37 ++++ util/ios/exception_processor.mm | 289 ++++++++++++++++++++++++++ 10 files changed, 519 insertions(+), 34 deletions(-) delete mode 100644 client/crashpad_client_ios_test.cc create mode 100644 client/crashpad_client_ios_test.mm create mode 100644 util/ios/exception_processor.h create mode 100644 util/ios/exception_processor.mm diff --git a/client/BUILD.gn b/client/BUILD.gn index dfdb3351..11ba757b 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -138,7 +138,7 @@ source_set("client_test") { } if (crashpad_is_ios) { - sources += [ "crashpad_client_ios_test.cc" ] + sources += [ "crashpad_client_ios_test.mm" ] sources -= [ "annotation_list_test.cc", "annotation_test.cc", diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index ba18947b..465867af 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -20,6 +20,7 @@ #include "base/strings/stringprintf.h" #include "client/client_argv_handling.h" #include "snapshot/ios/process_snapshot_ios.h" +#include "util/ios/exception_processor.h" #include "util/ios/ios_system_data_collector.h" #include "util/posix/signals.h" @@ -58,7 +59,6 @@ class SignalHandler { siginfo_t* siginfo, void* context) { HandleCrash(signo, siginfo, context); - // Always call system handler. Signals::RestoreHandlerAndReraiseSignalOnReturn( siginfo, old_actions_.ActionForSignal(signo)); @@ -84,6 +84,7 @@ CrashpadClient::CrashpadClient() {} CrashpadClient::~CrashpadClient() {} bool CrashpadClient::StartCrashpadInProcessHandler() { + InstallObjcExceptionPreprocessor(); return SignalHandler::Get()->Install(nullptr); } @@ -93,4 +94,5 @@ void CrashpadClient::DumpWithoutCrash() { siginfo_t siginfo = {}; SignalHandler::Get()->HandleCrash(siginfo.si_signo, &siginfo, nullptr); } + } // namespace crashpad diff --git a/client/crashpad_client_ios_test.cc b/client/crashpad_client_ios_test.cc deleted file mode 100644 index 6ed45794..00000000 --- a/client/crashpad_client_ios_test.cc +++ /dev/null @@ -1,32 +0,0 @@ -// 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 "client/crashpad_client.h" - -#include "gtest/gtest.h" - -namespace crashpad { -namespace test { -namespace { - -// TODO(justincohen): This is a placeholder. -TEST(CrashpadIOSClient, DumpWithoutCrash) { - crashpad::CrashpadClient client; - client.StartCrashpadInProcessHandler(); - client.DumpWithoutCrash(); -} - -} // namespace -} // namespace test -} // namespace crashpad diff --git a/client/crashpad_client_ios_test.mm b/client/crashpad_client_ios_test.mm new file mode 100644 index 00000000..357a7650 --- /dev/null +++ b/client/crashpad_client_ios_test.mm @@ -0,0 +1,56 @@ +// 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 "client/crashpad_client.h" + +#import <Foundation/Foundation.h> +#include <vector> + +#include "gtest/gtest.h" + +namespace crashpad { +namespace test { +namespace { + +// TODO(justincohen): This is a placeholder. +TEST(CrashpadIOSClient, DumpWithoutCrash) { + CrashpadClient client; + client.StartCrashpadInProcessHandler(); + client.DumpWithoutCrash(); +} + +// This test is covered by a similar XCUITest, but for development purposes +// it's sometimes easier and faster to run as a gtest. However, there's no +// way to correctly run this as a gtest. Leave the test here, disabled, for use +// during development only. +TEST(CrashpadIOSClient, DISABLED_ThrowNSException) { + CrashpadClient client; + client.StartCrashpadInProcessHandler(); + [NSException raise:@"GtestNSException" format:@"ThrowException"]; +} + +// This test is covered by a similar XCUITest, but for development purposes +// it's sometimes easier and faster to run as a gtest. However, there's no +// way to correctly run this as a gtest. Leave the test here, disabled, for use +// during development only. +TEST(CrashpadIOSClient, DISABLED_ThrowException) { + CrashpadClient client; + client.StartCrashpadInProcessHandler(); + std::vector<int> empty_vector = {}; + empty_vector.at(42); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 8ebdafa4..5369e3cf 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -145,4 +145,82 @@ XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); } +- (void)testException { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Crash the app. + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject crashException]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + +- (void)testNSException { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Crash the app. + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject crashNSException]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + +- (void)testCrashUnreocgnizedSelectorAfterDelay { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Crash the app. + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject crashUnreocgnizedSelectorAfterDelay]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + +- (void)testCatchNSException { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // The app should not crash + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject catchNSException]; + + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + +- (void)testRecursion { + // TODO(justincohen): Crashpad iOS does not currently support stack type + // crashes. + return; + + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Crash the app. + CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345]; + [rootObject crashRecursion]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + @end diff --git a/test/ios/host/application_delegate.mm b/test/ios/host/application_delegate.mm index a31d4d67..f8320857 100644 --- a/test/ios/host/application_delegate.mm +++ b/test/ios/host/application_delegate.mm @@ -14,6 +14,10 @@ #import "test/ios/host/application_delegate.h" +#include <dispatch/dispatch.h> + +#include <vector> + #import "Service/Sources/EDOHostNamingService.h" #import "Service/Sources/EDOHostService.h" #include "client/crashpad_client.h" @@ -75,4 +79,38 @@ abort(); } +- (void)crashException { + std::vector<int> empty_vector = {}; + empty_vector.at(42); +} + +- (void)crashNSException { + // EDO has its own sinkhole. + dispatch_async(dispatch_get_main_queue(), ^{ + NSArray* empty_array = @[]; + [empty_array objectAtIndex:42]; + }); +} + +- (void)catchNSException { + @try { + NSArray* empty_array = @[]; + [empty_array objectAtIndex:42]; + } @catch (NSException* exception) { + } @finally { + } +} + +- (void)crashUnreocgnizedSelectorAfterDelay { + [self performSelector:@selector(does_not_exist) withObject:nil afterDelay:1]; +} + +- (void)recurse { + [self recurse]; +} + +- (void)crashRecursion { + [self recurse]; +} + @end diff --git a/test/ios/host/cptest_shared_object.h b/test/ios/host/cptest_shared_object.h index 483fce47..70c814b0 100644 --- a/test/ios/host/cptest_shared_object.h +++ b/test/ios/host/cptest_shared_object.h @@ -35,6 +35,21 @@ // Trigger a crash with an abort(). - (void)crashAbort; + +// Trigger a crash with an uncaught exception. +- (void)crashException; + +// Trigger a crash with an uncaught NSException. +- (void)crashNSException; + +// Trigger an unrecognized selector after delay. +- (void)crashUnreocgnizedSelectorAfterDelay; + +// Trigger a caught NSxception. +- (void)catchNSException; + +// Trigger a crash with an infinite recursion. +- (void)crashRecursion; @end #endif // CRASHPAD_TEST_IOS_HOST_SHARED_OBJECT_H_ diff --git a/util/BUILD.gn b/util/BUILD.gn index 43b248e1..18cc112f 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -246,6 +246,8 @@ static_library("util") { if (crashpad_is_ios) { sources += [ + "ios/exception_processor.h", + "ios/exception_processor.mm", "ios/ios_system_data_collector.h", "ios/ios_system_data_collector.mm", "mac/xattr.cc", diff --git a/util/ios/exception_processor.h b/util/ios/exception_processor.h new file mode 100644 index 00000000..76a8c8b3 --- /dev/null +++ b/util/ios/exception_processor.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_UTIL_IOS_EXCEPTION_PROCESSOR_H_ +#define CRASHPAD_UTIL_IOS_EXCEPTION_PROCESSOR_H_ + +namespace crashpad { + +//! \brief Installs the Objective-C exception preprocessor. +//! +//! When code raises an Objective-C exception, unwind the stack looking for +//! any exception handlers. If an exception handler is encountered, test to +//! see if it is a function known to be a catch-and-rethrow 'sinkhole' exception +//! handler. Various routines in UIKit do this, and they obscure the +//! crashing stack, since the original throw location is no longer present +//! on the stack (just the re-throw) when Crashpad captures the crash +//! report. In the case of sinkholes, trigger an immediate exception to +//! capture the original stack. +//! +//! This should be installed at the same time the CrashpadClient installs the +//! signal handler. It should only be installed once. +void InstallObjcExceptionPreprocessor(); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_IOS_EXCEPTION_PROCESSOR_H_ diff --git a/util/ios/exception_processor.mm b/util/ios/exception_processor.mm new file mode 100644 index 00000000..818d4980 --- /dev/null +++ b/util/ios/exception_processor.mm @@ -0,0 +1,289 @@ +// 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 "util/ios/exception_processor.h" + +#import <Foundation/Foundation.h> +#include <TargetConditionals.h> +#include <cxxabi.h> +#include <dlfcn.h> +#include <libunwind.h> +#include <mach-o/loader.h> +#include <objc/objc-exception.h> +#include <objc/objc.h> +#include <objc/runtime.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <unwind.h> + +#include <exception> +#include <type_traits> +#include <typeinfo> + +#include "base/logging.h" +#include "base/strings/sys_string_conversions.h" +#include "build/build_config.h" + +namespace { + +// From 10.15.0 objc4-779.1/runtime/objc-exception.mm. +struct objc_typeinfo { + const void* const* vtable; + const char* name; + Class cls_unremapped; +}; +struct objc_exception { + id obj; + objc_typeinfo tinfo; +}; + +// From 10.15.0 objc4-779.1/runtime/objc-abi.h. +extern "C" const void* const objc_ehtype_vtable[]; + +// https://github.com/llvm/llvm-project/blob/09dc884eb2e4/libcxxabi/src/cxa_exception.h +static const uint64_t kOurExceptionClass = 0x434c4e47432b2b00; +struct __cxa_exception { +#if defined(ARCH_CPU_64_BITS) + void* reserve; + size_t referenceCount; +#endif + std::type_info* exceptionType; + void (*exceptionDestructor)(void*); + std::unexpected_handler unexpectedHandler; + std::terminate_handler terminateHandler; + __cxa_exception* nextException; + int handlerCount; + int handlerSwitchValue; + const unsigned char* actionRecord; + const unsigned char* languageSpecificData; + void* catchTemp; + void* adjustedPtr; +#if !defined(ARCH_CPU_64_BITS) + size_t referenceCount; +#endif + _Unwind_Exception unwindHeader; +}; + +objc_exception_preprocessor g_next_preprocessor; +bool g_exception_preprocessor_installed; + +void TerminatingFromUncaughtNSException(id exception, const char* sinkhole) { + // TODO(justincohen): This is incomplete, as the signal handler will not have + // access to the exception name and reason. Pass that along somehow here. + NSString* exception_message_ns = [NSString + stringWithFormat:@"%@: %@", [exception name], [exception reason]]; + std::string exception_message = base::SysNSStringToUTF8(exception_message_ns); + LOG(INFO) << "Terminating from Objective-C exception: " << exception_message + << " with sinkhole: " << sinkhole; + // TODO(justincohen): This is temporary, as crashpad can capture this + // exception directly instead. + std::terminate(); +} + +// Returns true if |path| equals |sinkhole| on device. Simulator paths prepend +// much of Xcode's internal structure, so check that |path| ends with |sinkhole| +// for simulator. +bool ModulePathMatchesSinkhole(const char* path, const char* sinkhole) { +#if TARGET_OS_SIMULATOR + size_t path_length = strlen(path); + size_t sinkhole_length = strlen(sinkhole); + if (sinkhole_length > path_length) + return false; + return strncmp(path + path_length - sinkhole_length, + sinkhole, + sinkhole_length) == 0; +#else + return strcmp(path, sinkhole) == 0; +#endif +} + +id ObjcExceptionPreprocessor(id exception) { + // Unwind the stack looking for any exception handlers. If an exception + // handler is encountered, test to see if it is a function known to catch- + // and-rethrow as a "top-level" exception handler. Various routines in + // Cocoa/UIKit do this, and it obscures the crashing stack, since the original + // throw location is no longer present on the stack (just the re-throw) when + // Crashpad captures the crash report. + unw_context_t context; + unw_getcontext(&context); + + unw_cursor_t cursor; + unw_init_local(&cursor, &context); + + static const void* this_base_address = []() -> const void* { + Dl_info dl_info; + if (!dladdr(reinterpret_cast<const void*>(&ObjcExceptionPreprocessor), + &dl_info)) { + LOG(ERROR) << "dladdr: " << dlerror(); + return nullptr; + } + return dl_info.dli_fbase; + }(); + + // Generate an exception_header for the __personality_routine. + // From 10.15.0 objc4-779.1/runtime/objc-exception.mm objc_exception_throw. + objc_exception* exception_objc = reinterpret_cast<objc_exception*>( + __cxxabiv1::__cxa_allocate_exception(sizeof(objc_exception))); + exception_objc->obj = exception; + exception_objc->tinfo.vtable = objc_ehtype_vtable + 2; + exception_objc->tinfo.name = object_getClassName(exception); + exception_objc->tinfo.cls_unremapped = object_getClass(exception); + + // https://github.com/llvm/llvm-project/blob/c5d2746fbea7/libcxxabi/src/cxa_exception.cpp + // __cxa_throw + __cxa_exception* exception_header = + reinterpret_cast<__cxa_exception*>(exception_objc) - 1; + exception_header->unexpectedHandler = std::get_unexpected(); + exception_header->terminateHandler = std::get_terminate(); + exception_header->exceptionType = + reinterpret_cast<std::type_info*>(&exception_objc->tinfo); + exception_header->unwindHeader.exception_class = kOurExceptionClass; + + bool handler_found = false; + while (unw_step(&cursor) > 0) { + unw_proc_info_t frame_info; + if (unw_get_proc_info(&cursor, &frame_info) != UNW_ESUCCESS) { + continue; + } + + if (frame_info.handler == 0) { + continue; + } + + // Check to see if the handler is really an exception handler. + __personality_routine p = + reinterpret_cast<__personality_routine>(frame_info.handler); + + // From 10.15.0 libunwind-35.4/src/UnwindLevel1.c. + _Unwind_Reason_Code personalityResult = (*p)( + 1, + _UA_SEARCH_PHASE, + exception_header->unwindHeader.exception_class, + reinterpret_cast<_Unwind_Exception*>(&exception_header->unwindHeader), + reinterpret_cast<_Unwind_Context*>(&cursor)); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + break; + case _URC_CONTINUE_UNWIND: + continue; + default: + break; + } + + char proc_name[512]; + unw_word_t offset; + if (unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &offset) != + UNW_ESUCCESS) { + // The symbol has no name, so see if it belongs to the same image as + // this function. + Dl_info dl_info; + if (dladdr(reinterpret_cast<const void*>(frame_info.start_ip), + &dl_info)) { + if (dl_info.dli_fbase == this_base_address) { + // This is a handler in our image, so allow it to run. + handler_found = true; + break; + } + } + + // This handler does not belong to us, so continue the search. + continue; + } + + // Check if the function is one that is known to obscure (by way of + // catch-and-rethrow) exception stack traces. If it is, sinkhole it + // by crashing here at the point of throw. + constexpr const char* kExceptionSymbolNameSinkholes[] = { + // The two CF symbol names will also be captured by the CoreFoundation + // library path check below, but for completeness they are listed here, + // since they appear unredacted. + "CFRunLoopRunSpecific", + "_CFXNotificationPost", + "__NSFireDelayedPerform", + }; + for (const char* sinkhole : kExceptionSymbolNameSinkholes) { + if (strcmp(sinkhole, proc_name) == 0) { + TerminatingFromUncaughtNSException(exception, sinkhole); + } + } + + // On iOS, function names are often reported as "<redacted>", although they + // do appear when attached to the debugger. When this happens, use the path + // of the image to determine if the handler is an exception sinkhole. + constexpr const char* kExceptionLibraryPathSinkholes[] = { + // Everything in this library is a sinkhole, specifically + // _dispatch_client_callout. Both are needed here depending on whether + // the debugger is attached (introspection only appears when a simulator + // is attached to a debugger. + // only). + "/usr/lib/system/introspection/libdispatch.dylib", + "/usr/lib/system/libdispatch.dylib", + + // __CFRunLoopDoTimers and __CFRunLoopRun are sinkholes. Consider also + // checking that a few frames up is CFRunLoopRunSpecific(). + "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"}; + + Dl_info dl_info; + if (dladdr(reinterpret_cast<const void*>(frame_info.start_ip), &dl_info) != + 0) { + for (const char* sinkhole : kExceptionLibraryPathSinkholes) { + if (ModulePathMatchesSinkhole(dl_info.dli_fname, sinkhole)) { + TerminatingFromUncaughtNSException(exception, sinkhole); + } + } + } + + handler_found = true; + + break; + } + + // If no handler is found, __cxa_throw would call failed_throw and terminate. + // See: + // https://github.com/llvm/llvm-project/blob/c5d2746fbea7/libcxxabi/src/cxa_exception.cpp + // __cxa_throw. Instead, terminate via TerminatingFromUncaughtNSException so + // the exception name and reason are properly recorded. + if (!handler_found) { + TerminatingFromUncaughtNSException(exception, "__cxa_throw"); + } + + // Forward to the next preprocessor. + if (g_next_preprocessor) + return g_next_preprocessor(exception); + + return exception; +} + +} // namespace + +namespace crashpad { + +void InstallObjcExceptionPreprocessor() { + DCHECK(!g_exception_preprocessor_installed); + + g_next_preprocessor = + objc_setExceptionPreprocessor(&ObjcExceptionPreprocessor); + g_exception_preprocessor_installed = true; +} + +void UninstallObjcExceptionPreprocessor() { + DCHECK(g_exception_preprocessor_installed); + + objc_setExceptionPreprocessor(g_next_preprocessor); + g_next_preprocessor = nullptr; + g_exception_preprocessor_installed = false; +} + +} // namespace crashpad From b71a4f1ca8f9f58a06bb6030cc27609430e946d6 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Thu, 9 Apr 2020 17:05:33 -0400 Subject: [PATCH 370/401] doc: Update buildbot URL Change-Id: I7a1b6b91cb3f549904e2b930dab8becaca13085c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2144915 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- doc/developing.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/developing.md b/doc/developing.md index 406a234f..431ca1d5 100644 --- a/doc/developing.md +++ b/doc/developing.md @@ -328,7 +328,7 @@ file. ## Buildbot -The [Crashpad Buildbot](https://build.chromium.org/p/client.crashpad/) performs -automated builds and tests of Crashpad. Before checking out or updating the -Crashpad source code, and after checking in a new change, it is prudent to check -the Buildbot to ensure that “the tree is green.” +The [Crashpad Buildbot](https://ci.chromium.org/p/crashpad/g/main/console) +performs automated builds and tests of Crashpad. Before checking out or updating +the Crashpad source code, and after checking in a new change, it is prudent to +check the Buildbot to ensure that “the tree is green.” From 054f45724e685f6a6aba501c836284e716fa00fb Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Thu, 9 Apr 2020 21:24:11 +0000 Subject: [PATCH 371/401] Revert "fuchsia: Include reference to zx library" This reverts commit de5bc33b8b45b197977430a0e74a37c00c6a3bc3. Reason for revert: going to be removed back out of the SDK, transitions are hard :( https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=7802#c33 Original change's description: > fuchsia: Include reference to zx library > > "library zx" used to be built in to fidlc, but is now a standalone file > (this is an SDK change). Update the build rules to adapt to this. > > ref: https://logs.chromium.org/logs/crashpad/buildbucket/cr-buildbucket.appspot.com/8883567878548782112/+/steps/compile_with_ninja/0/stdout > > FAILED: gen/fidl/include/fuchsia/sysinfo/c/client.cc gen/fidl/include/fuchsia/sysinfo/c/fidl.h gen/third_party/fuchsia/fidl/fuchsia.sysinfo/tables.c gen/third_party/fuchsia/fidl/fuchsia.sysinfo/intermediary_representation.json > python ../../third_party/fuchsia/runner.py ../../third_party/fuchsia/sdk/linux-amd64/tools/fidlc --c-header gen/fidl/include/fuchsia/sysinfo/c/fidl.h --c-client gen/fidl/include/fuchsia/sysinfo/c/client.cc --tables gen/third_party/fuchsia/fidl/fuchsia.sysinfo/tables.c --json gen/third_party/fuchsia/fidl/fuchsia.sysinfo/intermediary_representation.json --name fuchsia.sysinfo --files ../../third_party/fuchsia/sdk/linux-amd64/fidl/fuchsia.sysinfo/sysinfo.fidl > ../../third_party/fuchsia/sdk/linux-amd64/fidl/fuchsia.sysinfo/sysinfo.fidl:7:7: error: Could not find library named zx. Did you include its sources with --files? > using zx; > ^~ > > Bug: fuchsia:7802 > Change-Id: I10c0109fd9621a19d72deb21a489c2041caeeeca > Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2141019 > Commit-Queue: Scott Graham <scottmg@chromium.org> > Commit-Queue: Justin Cohen <justincohen@chromium.org> > Reviewed-by: Justin Cohen <justincohen@chromium.org> TBR=justincohen@chromium.org,scottmg@chromium.org Change-Id: I0328c2ff586ff733926a51d87774453cb2cf7c33 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: fuchsia:7802 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2143940 Reviewed-by: Scott Graham <scottmg@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- third_party/fuchsia/BUILD.gn | 2 -- 1 file changed, 2 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 71a648eb..4111c582 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -156,8 +156,6 @@ if (crashpad_is_in_fuchsia) { "--name", fidl_source.library_name, "--files", - rebase_path("$sdk_fidl_sources_path/zx/zx_common.fidl", root_build_dir), - "--files", rebase_path(fidl_source.fidl, root_build_dir), ] From 380f2108dfb0ed5b7a8d7b3a3427af67a5e58ab6 Mon Sep 17 00:00:00 2001 From: Victor Costan <pwnall@chromium.org> Date: Fri, 10 Apr 2020 21:23:25 -0700 Subject: [PATCH 372/401] Roll crashpad/third_party/gtest/gtest/ eb78ee170..e3f0319d8 (232 commits) https://chromium.googlesource.com/external/github.com/google/googletest/+log/eb78ee170ac9..e3f0319d89f4 This CL also removes references to gmock-generated-matchers.h, which was removed from googletest in commit 41b5f149ab306e96b5b2faf523505d75acffd98a, and to gmock-generated-function-mockers.h, which was removed from googletest in commit fbf67a70d07543f40832d0cd7a58f304bc6ab1d1. $ git log eb78ee170..e3f0319d8 --oneline --abbrev=12 --reverse 130e5aa86a7a Merge pull request #2 from google/master 6fd262ecf787 Prepare for Bazel incompatible changes 800c9b30168f Update Bazel on Windows 2c2c9e33573d remove a custom implementation of std::add_lvalue_reference 11471da7938b remove a custom implementation of std::enable_if e2c06aa2497e remove a custom implementation of std::iterator_traits 364839ab142e remove a custom implementation of std::remove_const da76d01b984f remove a custom implementation of std::is_reference 6a015ca1cb4e reuse IndexSequence from googletest 44de8697835d remove a dead metafunction 27e17f7851e2 Googletest export 410b52985e3d Googletest export fcffabb5beb8 Googletest export 30e58a89a42b Merge pull request #2381 from Yannic:fix_bazel d5e9e0c38f85 Merge pull request #2397 from kuzkry:custom-type-traits-is_reference c9ccac7cb734 Googletest export 7bd4a7f3e9ae restore mistakenly removed iffs in their explicit form d1ad644db4b9 Googletest export fb49e6c16449 Merge pull request #2393 from kuzkry:custom-type-traits-remove_const f8e9b3767ff8 remove references to autotools and combine gTest&gMock sections 9bf34ace7194 Merge pull request #2400 from kuzkry:custom-type-traits-enable_if c6d884096ae5 Merge pull request #2401 from kuzkry:custom-type-traits-add_lvalue_reference 46525e1e5dfc Merge pull request #2394 from kuzkry:custom-type-traits-duplication-of-custom-index_sequence db1b739943e9 Googletest export ed2eef654373 Googletest export 38ce18e8e662 post-review to db1b7399 (#2396) 6a3d632f40a1 Googletest export fdd6a1dc8c74 Merge pull request #2382 from kuzkry:dead-metafunction 85f059f03d56 Merge pull request #3 from google/master d9c55a48eddb Merge pull request #2426 from kuzkry:#2396-postreview eb56ee5a28b4 Googletest export a648da952b79 Merge pull request #2420 from kuzkry:remove-autotools-section 565f1b848215 Merge pull request #2398 from kuzkry:custom-type-traits-iterator_traits ab8f346b076f Googletest export 6123df929dba Googletest export 3f05f651ae36 Googletest export c2b2cd8883f5 Googletest export 62a109a2ffe6 Googletest export 3a4503986247 Googletest export bafa644c182e remove a dead function 838ea5cea301 remove GTEST_HAS_STD_STRING 33a0d4f6d76a Googletest export 0cd3fbc8abe6 change includes in gtest-port.h 274afe50cf57 Googletest export ac24edd6e061 Googletest export c7a03daa99e7 Merge pull request #2387 from kuzkry:iff c96da8fea82e change usings cad3bc46c2ba Googletest export f2fb48c3b3d7 Googletest export 7c2bd3af981e square away the stuff that hasn't been merged in a manual review 3339b97c6a7f square away the stuff that hasn't been merged in a manual review 90a8ab70a1f6 mention the existing support for wide strings in string matchers e0d16aa33662 remove GTEST_ARRAY_SIZE_ 2460f97152c9 Add many missing override keywords c78ea26f2008 Bump llvm version to 4 so brew can work again 076c46198fe1 Googletest export bf0fe874a27b Googletest export a783ade7c244 Googletest export cb3f7ce1deef Googletest export 72adf7a4155b Googletest export dc1ca9ae4c20 Googletest export 51f7396d4058 Fix typo in documents 68319c19eb01 Googletest export 4105eb726341 Googletest export 703bd9caab50 (tag: v1.10.x, tag: release-1.10.0) Googletest export 76a560c81cfe Googletest export 5126ff48d9ac Revert "Use pcfiledir for prefix in pkgconfig file" b96832a44b49 Add documentation for pkg-config in cross-compilation settings 4360e4267c1e Merge pull request #2491 from SoapGentoo:fix-GNUInstallDirs-pkg-config 2ed2211db99a Use FormatFileLocation for streaming file and line 3f5a8c6ee6ce Merge pull request #2495 from hyukmyeong:typo 10c1d8c4faed Use the verbatim noexcept spec in MOCKED_METHOD 0eadff8a932d Fix spacing 872b9ceb6045 Avoid comma operator 7f8617a7c532 Switch to free function to avoid GCC bug 20255e6f4099 Use declval in noexcept expression cd17fa2abda2 Merge pull request #2475 from peterbarker:pr/google-add-override de69803b1e38 Mention Cornichon as a related open source project cb1d5db1a104 Merge pull request #2448 from kuzkry:bad-googletest-export 5395345ca4f0 Merge pull request #2497 from thejcannon:handle_null_filename 20b5b8ecc7a8 Googletest export 58c71977611c Merge pull request #2505 from zebmason:cornichon bc996e0817d8 Made noexcept condition more exciting 31406d79090e chore: update version 9b9700247d46 clean-up broken paths for PlatformIO ed78e54f38ab Googletest export a4a5a7c768ce Googletest export 37905b9d8c8f Merge pull request #2498 from thejcannon:noexcept_spec eafd2a91bb0c Merge pull request #2456 from kuzkry:gtest-port-clean-up_breaking-changes a3ca5b9e0bf9 Googletest export ba513d2c9525 Merge pull request #2498 from thejcannon:noexcept_spec c081ceebfb6f Workaround MSVC VA_ARGS weirdness c1e8e71aab60 Add a compile test d935e8e3edaf Fix preprocessor tests fe112cfee7e7 Replace compile-test with preprocessor test 5fe523361243 Removing extraneous test 40a6b9662199 feat: Add support for ESP8266 platform c2206b05aa0f Add ESP8266 configs to PlatformIO build f8961b99f4c3 Evaluate and cat NARG in different macros 3e813465a46b Removing extraneous parenthesis 84a5ae8b8560 Update to distinguish prelease purpose of this fork. 3cddd56e195b Add more override keywords e1b67b07f7bd Avoid recursive macros 778733f9ecdd feat: Add ESP8266 support 9e466f1eb0fa Merge pull request #2510 from ciband:chore/update_pio_version 4c25e2b87fcb Googletest export bdc29d5dc19d Merge pull request #2421 from kuzkry:cleanup-for-regex cbf019de22c8 [googletest] Output skip message 2995ca563d76 Merge pull request #2507 from roblub:master bbe4b7363bba Googletest export 1f9edcd96981 Googletest export f966ed158177 Googletest export 5f92697d46ae Fix Issue 2418 f164a9e23c0f Remove extra space 011c4e23d525 Googletest export 8ce64c084d83 Merge pull request #2454 from kuzkry:gtest-port-clean-up_dead-function a5216dd1a9f3 Merge pull request #2511 from kuzkry:PlatformIO-clean-up 611a321a6e64 Googletest export de1128355464 Merge pull request #2444 from kuzkry:remove-GTEST_ARRAY_SIZE_ 8c91ecef292e Merge pull request #2517 from snarkmaster:master b11fb80e9e94 Prevent using ReturnRef on reference to temporary f1afeaa64348 Googletest export 19a3bbce512d Added tests verifying that temporaries are accepted by ReturnRef 37590da6c08f Added more tests to verify: ReturnRef not accept temporary aa1146da8169 Googletest export 8bab7883a676 Merge pull request #2514 from thejcannon:msvc_macro_issue 1110c471cadf Merge pull request #2522 from cloudrex:patch-1 676d0444bf95 Revert "Merge pull request #2498 from thejcannon:noexcept_spec" 37f322783175 Googletest export 6e87238c9b14 remove BiggestInt d072682119f8 Tests simplified and names corrected (POD->scalar) 5ff72f5295f3 Apply 80chars limit 208c2f6b6076 variable names corrected (followed google coding style) 540835fa687e Merge pull request #2515 from ciband:feat/support_esp8266 eed64b5fc6c0 replace autogenerated TypesX classes by variadic ones e3a9a567d826 replace autogenerated TemplatesX classes by variadic ones a7083564d550 remove gtest-type-util.h.pump 002905f29fc9 move the pumping script to googlemock 1a49b67aebe9 update CONTRIBUTORS a8b1a66cfda3 Merge pull request #2388 from kuzkry:remove-gtest-type-util.pump a1f71dd56df4 Googletest export b5fb5ba05cb6 Merge pull request #2527 from PiotrNycz:gmock_prevent_return_ref_to_store_temporaries_2 757d39a79bcb Googletest export 755f853c6be9 Googletest export 2bee6da24e9f Googletest export fff8dabbf6c5 Googletest export ba33a8876c3e Googletest export f626deda19e5 Added special catch for std::exception in GTEST_TEST_NO_THROW_ 0a03480824b4 Googletest export e2fc3a9c9cb8 Googletest export 2db3df9c4f82 Googletest export 057ee5063d00 Merge pull request #2533 from thejcannon:noexcept_spec e8a82dc7ede6 Merge pull request #2453 from kuzkry:gtest-port-clean-up_kMaxBiggestInt 523ad489efc3 update pump_manual.md 442f45b376f5 pump.py: add support for Python 3 f658561ef253 fix a typo 8697709e0308 Merge pull request #2453 from kuzkry:gtest-port-clean-up_kMaxBiggestInt f9665846e405 update gen_gtest_pred_impl.py f79ac2ce0e78 change incorrect comments 6caa879a42d9 pkg-config: Remove pthread link flag from Cflags 3e062a6efe7a Merge pull request #2373 from Youw:master 54978626b40f Merge pull request #2547 from kuzkry:typo 8aedd597af6b Merge pull request #2548 from kuzkry:update-pump-manual e08a4602778b Merge pull request #2549 from kuzkry:pump-support-for-python-3 681454dae48f Googletest export d5707695cb02 Googletest export dee725b05332 add documentation for the premature-exit-file protocol 11440f27c66d Merge pull request #2556 from ienorand:avoid-pkg-config-lpthread-cflag f73898f3ffd4 Merge pull request #2554 from kuzkry:update-gen_gtest_pred_impl c27acebba3b3 Merge pull request #2521 from Sinclair-John:master 0c469a5a065e Fix FlatTuple compilation on older msvc. dcdb65065f41 Fix internal memory leak in Windows _Crt report. 50cfbb726b26 Googletest export 4bf466236dbe Googletest export 200ff599496e Merge pull request #2569 from bgianfo:master 6a9d6d5c28a7 Fix compile break for Microsoft Visual Studio 2017 v141 2241be0c3f24 remove g++ 3.3 workaround: using on operator<< e1dd49835ef2 remove g++ 2.95.0 workaround: no space after first comma in macros a91e4e73b702 remove stale comments about older GCC versions 21d276b5c42d remove MSVC workaround: accessing namespace scope from within nested classes a5136dbdd21e remove MSVC workaround: error C2665 ecefcbd4aa71 remove MSVC workaround: warning 4355 6748df1eab1d remove MSVC workaround: cease const dropping e0c80b0a6e51 consistency fix for SafeMatcherCastImpl member functions bbbc5d8a4b90 remove Nokia's Symbian compiler workaround: SafeMatcherCastImpl 298a40f023e6 remove MSVC workaround: wmain link error in the static library a909becdc599 unify googletest and googlemock main functions 717ce7feb872 Googletest export af71b6607f9e Merge pull request #2570 from xieyubo:1.10 679bfec6db73 Googletest export 838a32845c64 Fixed typo 5a62d400e057 README.md: added Catch2 and Google Test Explorer 51545ee515fc Googletest export a32a20009473 Merge pull request #2588 from kuzkry:remove-workaround_g++-incorrect-comments 7a8a5bcec005 Merge pull request #2591 from kuzkry:remove-workaround_g++-using-on-operator<< be74b4b2e0d1 Googletest export db13ff1f0bd5 Merge pull request #2597 from kuzkry:remove-workaround_Nokia-Sybian-SafeMatcherCastImpl 0361bdf591dd Merge pull request #2596 from kuzkry:remove-workaround_msvc-wmain-link-error 39803f3c51d2 Merge pull request #2593 from kuzkry:remove-workaround_msvc-namespace-scope-from-nested-class 34e92be31cf4 Merge pull request #2604 from matepek:readme-update-with-opensource-proj b8a92f7c86e4 Rename test case to test suite 967d8e05c2f0 Revert "unify googletest and googlemock main functions" 3957b8898b58 Revert "remove MSVC workaround: wmain link error in the static library" b155875f32dc Merge pull request #2583 from ChristophStrehle:master 11a9482f84ac Merge pull request #2607 from oyefremov:patch-1 52825d78aac6 Merge pull request #2603 from maximilianschwab:patch-1 ae8d1fc81b14 Googletest export cf75d4b92ecc Googletest export 1d563578c86f Merge pull request #2594 from kuzkry:remove-workaround_msvc-unneeded-const-dropping 2002f267f05b Googletest export 9ed99c6c837a Googletest export 78fdd6c00b8f Merge pull request #2609 from kuzkry:revert-2596 20b8e7a1c827 Activate GNU extensions in case of MSYS generator 6251071a20e8 Googletest export a3097c826e4d Merge pull request #2592 from kuzkry:remove-workaround_msvc-error-C2665 88ba008c234a Merge pull request #2595 from kuzkry:remove-workaround_msvc-warning-4355 d442089d53ce Googletest export d8eeb9760afc Googletest export d16f86ff1cac Googletest export 5b162a79d49d Merge pull request #2589 from kuzkry:remove-workaround_g++-no-space-after-first-macro-argument d2016469064b Workaround VS bug w.r.t empty arguments to macros 4b7809c2f523 Revert "Googletest export": Remove test for empty prefix 1800a38fb7d8 Revert "Googletest export": disallow empty prefix 0a0c82662992 Googletest export d166e0948384 Merge pull request #2590 from kuzkry:remove-workaround_g++-stale-comments 9d8222ad6672 Disable move constructor and assignment operator for test classes. 77b3a250ea9e Review notes: Return T& from assignment operators 05701fee2896 Deleted functions as part of public interface cc05a3ca014b Define default destructor for test classes bf31ed376ab1 Make move operation noexcept. 6f1a8ffde934 Googletest export d0a521255eb5 Googletest export 008629ae2163 Merge pull request #2624 from ShabbyX:master a13a0626188b Googletest export fbe34cecf4ff Merge pull request #2639 from trzecieu:trzeci/move_ctor_assign 153909f09633 Googletest export 0d98d87e1069 Googletest export 07ab939af757 Merge pull request #2632 from Kravlalala:cmake/mingw_msys_build 306f3754a71d Googletest export 4b9c1691c4b7 Googletest export 8417b7332210 Googletest export c901f67ddf8a Googletest export d854bd6acc47 Googletest export 3aa538cbfcc6 fix unit test failure on NoShortCircuitOnFailure and DetectsFlakyShortCircuit when GTEST_HAS_RTTI is 1 c7137f0b8422 Use IsReadableTypeName IsReadableTypeName in OfType function in gmock-matchers_test.cc aa4315646b22 Remove exclusion of *-main and*-all targets ed16134fb313 Googletest export 0b024bd91a14 Googletest export 7a8591e6e4e2 Googletest export 3e79d366e380 Googletest export 5336106b66db Googletest export 8b4817e3df37 Googletest export 18b67bfc58b1 Googletest export c59c7bab5056 Merge pull request #2672 from ivan1993br:ivan1993br-platformio_update 9417fb401a57 Merge pull request #2665 from bysreg:fix_noshortcircuitfailure_detectsflakyshortcircuit_test d01e356e155a Googletest export 10b1902d893e Googletest export c378d7eb9308 remove a dead reference to the Autotools script 22397f28ef57 Googletest export f1a6db9d4a8c Googletest export 87061810f4c7 Googletest export 7413280c52c1 Googletest export d6ce39edf612 Googletest export 38f6608e8790 Googletest export 7bc671b8e0de Googletest export 572e261b6075 Googletest export 74b44b2d0fc2 Googletest export 4f6609129a2f Googletest export d02e2772750f Googletest export 11d9834e98c1 Googletest export fbf67a70d075 Googletest export 2d6d7a01c9ce Googletest export 41b5f149ab30 Googletest export 139fa202c938 Googletest export 360f5f70a3ff Googletest export 56de7cc8b554 Googletest export d0930731d601 Googletest export 6f5fd0d7199b Googletest export 23b2a3b1cf80 Googletest export 04e52ebe7816 Fixed warnings fd538161f484 Googletest export 909b1ccfcacc Googletest export e588eb1ff9ff Googletest export a1b0173df92b Make sure IsATTY does not clobber errno. cfb5ef4e7dc0 Googletest export 878bd92e0fef Merge pull request #2716 from kuzkry:autotools-leftover 3de76551e0f0 Merge pull request #2722 from JohanMabille:warnings 0bf8ea3065f7 Googletest export 230afdb24e0f Googletest export 227faf41db5e Googletest export c43f7100f084 Googletest export 482ac6ee6342 Googletest export e41f31f2af3a Add tests for MockFunction deduction (#2277) 53740ebc21d5 Add support for std::function in MockFunction (#2277) dbe804f98621 Merge pull request #2746 from Romain-Geissler-1A:master 749148f1accc Googletest export 08347d7a1604 Swap settimer and sigaction calls to avoid SIGPROF 82e5767f7812 remove dead code in googletest-output-test acabdf65fba1 remove chapters on Autotools, Meson and plain Makefiles 1ced315a483f Googletest export 67cc66080d64 Merge pull request #2350 from adambadura:MockFunctionFromStdFunction 01e4fbf5ca60 Merge pull request #2764 from kuzkry:googletest-output-test-dead-code dc82a33473dd Merge pull request #2765 from kuzkry:unsupported-build-systems 61f010d703b3 Googletest export c344cb5a8d2b Googletest export 7084afda5aa3 Merge pull request #2762 from pkryger:avoid_sigprof e3f0319d89f4 Merge pull request #2715 from kuzkry:document-premature-exit-file-protocol Created with: roll-dep crashpad/third_party/gtest/gtest Bug: 1070043 Change-Id: I39ab84ab931fa469cf8922a2d33d9b2b4e04cf4e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2145627 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Victor Costan <pwnall@chromium.org> --- DEPS | 2 +- third_party/gtest/BUILD.gn | 3 --- third_party/gtest/gmock.gyp | 3 --- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/DEPS b/DEPS index 43334df2..b4f2ad26 100644 --- a/DEPS +++ b/DEPS @@ -33,7 +33,7 @@ deps = { }, 'crashpad/third_party/gtest/gtest': Var('chromium_git') + '/external/github.com/google/googletest@' + - 'eb78ee170ac9eb21487f4d127720c060351fa8a2', + 'e3f0319d89f4cbf32993de595d984183b1a9fc57', 'crashpad/third_party/gyp/gyp': Var('chromium_git') + '/external/gyp@' + '8bee09f4a57807136593ddc906b0b213c21f9014', diff --git a/third_party/gtest/BUILD.gn b/third_party/gtest/BUILD.gn index 28137681..4764604c 100644 --- a/third_party/gtest/BUILD.gn +++ b/third_party/gtest/BUILD.gn @@ -291,8 +291,6 @@ if (crashpad_is_in_chromium) { "gtest/googlemock/include/gmock/gmock-cardinalities.h", "gtest/googlemock/include/gmock/gmock-function-mocker.h", "gtest/googlemock/include/gmock/gmock-generated-actions.h", - "gtest/googlemock/include/gmock/gmock-generated-function-mockers.h", - "gtest/googlemock/include/gmock/gmock-generated-matchers.h", "gtest/googlemock/include/gmock/gmock-matchers.h", "gtest/googlemock/include/gmock/gmock-more-actions.h", "gtest/googlemock/include/gmock/gmock-more-matchers.h", @@ -342,7 +340,6 @@ if (crashpad_is_in_chromium) { "gtest/googlemock/test/gmock-cardinalities_test.cc", "gtest/googlemock/test/gmock-function-mocker_test.cc", "gtest/googlemock/test/gmock-generated-actions_test.cc", - "gtest/googlemock/test/gmock-generated-function-mockers_test.cc", "gtest/googlemock/test/gmock-generated-matchers_test.cc", "gtest/googlemock/test/gmock-internal-utils_test.cc", "gtest/googlemock/test/gmock-matchers_test.cc", diff --git a/third_party/gtest/gmock.gyp b/third_party/gtest/gmock.gyp index 499792f9..10c0879a 100644 --- a/third_party/gtest/gmock.gyp +++ b/third_party/gtest/gmock.gyp @@ -58,8 +58,6 @@ '<(gmock_dir)/include/gmock/gmock-cardinalities.h', '<(gmock_dir)/include/gmock/gmock-function-mocker.h', '<(gmock_dir)/include/gmock/gmock-generated-actions.h', - '<(gmock_dir)/include/gmock/gmock-generated-function-mockers.h', - '<(gmock_dir)/include/gmock/gmock-generated-matchers.h', '<(gmock_dir)/include/gmock/gmock-matchers.h', '<(gmock_dir)/include/gmock/gmock-more-actions.h', '<(gmock_dir)/include/gmock/gmock-more-matchers.h', @@ -160,7 +158,6 @@ '<(gmock_dir)/test/gmock-cardinalities_test.cc', '<(gmock_dir)/test/gmock-function-mocker_test.cc', '<(gmock_dir)/test/gmock-generated-actions_test.cc', - '<(gmock_dir)/test/gmock-generated-function-mockers_test.cc', '<(gmock_dir)/test/gmock-generated-matchers_test.cc', '<(gmock_dir)/test/gmock-internal-utils_test.cc', '<(gmock_dir)/test/gmock-matchers_test.cc', From e621aaa1322819005c394818f1fd2b5a94dd2ccd Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 10 Apr 2020 17:40:41 -0400 Subject: [PATCH 373/401] =?UTF-8?q?Make=20=E2=80=9Cgn=20check=E2=80=9D=20p?= =?UTF-8?q?ass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ia7a215e1a2d0a3b1868b00c5d47b46ef8a675cdc Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2144917 Reviewed-by: Justin Cohen <justincohen@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- handler/BUILD.gn | 4 ++++ minidump/BUILD.gn | 30 ++++++++++++++++++++---- snapshot/BUILD.gn | 27 ++++++++++++++++++--- snapshot/crashpad_info_client_options.cc | 1 - snapshot/ios/module_snapshot_ios.h | 1 - third_party/fuchsia/BUILD.gn | 3 --- third_party/zlib/BUILD.gn | 2 +- util/win/exception_handler_server.cc | 3 --- 8 files changed, 55 insertions(+), 16 deletions(-) diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 3db3c899..2f608cb1 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -133,6 +133,8 @@ source_set("handler_test") { ] if (crashpad_is_win) { + deps += [ "../minidump:test_support" ] + data_deps = [ ":crashpad_handler_test_extended_handler", ":fake_handler_that_crashes_at_startup", @@ -149,6 +151,7 @@ if (!crashpad_is_ios) { "../build:default_exe_manifest_win", "../compat", "../third_party/mini_chromium:base", + "../tools:tool_support", ] if (crashpad_is_win) { @@ -223,6 +226,7 @@ if (crashpad_is_win) { "../build:default_exe_manifest_win", "../compat", "../third_party/mini_chromium:base", + "../tools:tool_support", ] } diff --git a/minidump/BUILD.gn b/minidump/BUILD.gn index 35b19172..44425857 100644 --- a/minidump/BUILD.gn +++ b/minidump/BUILD.gn @@ -20,15 +20,12 @@ static_library("minidump") { "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", @@ -71,7 +68,10 @@ static_library("minidump") { public_configs = [ "..:crashpad_config" ] - public_deps = [ "../compat" ] + public_deps = [ + ":format", + "../compat", + ] deps = [ "../snapshot", @@ -87,6 +87,25 @@ static_library("minidump") { } } +# :format is the only part of minidump that snapshot may depend on. +static_library("format") { + sources = [ + "minidump_context.h", + "minidump_extensions.cc", + "minidump_extensions.h", + ] + + public_configs = [ "..:crashpad_config" ] + + public_deps = [ "../compat" ] + + deps = [ + "../snapshot:context", + "../third_party/mini_chromium:base", + "../util", + ] +} + static_library("test_support") { testonly = true @@ -114,8 +133,11 @@ static_library("test_support") { public_deps = [ ":minidump" ] deps = [ + "../snapshot:test_support", + "../test", "../third_party/gtest:gtest", "../third_party/mini_chromium:base", + "../util", ] if (crashpad_is_win) { diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index 3924c175..fea22c2a 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -28,9 +28,6 @@ static_library("snapshot") { "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", @@ -244,9 +241,12 @@ static_library("snapshot") { public_configs = [ "..:crashpad_config" ] + public_deps = [ ":context" ] + deps = [ "../client", "../compat", + "../minidump:format", "../third_party/mini_chromium:base", "../util", ] @@ -263,6 +263,26 @@ static_library("snapshot") { configs += [ "..:disable_ubsan" ] } +# :context is the only part of snapshot that minidump may depend on. +static_library("context") { + sources = [ + "cpu_architecture.h", + "cpu_context.cc", + "cpu_context.h", + ] + + public_configs = [ "..:crashpad_config" ] + + deps = [ + "../third_party/mini_chromium:base", + "../util", + ] + + if (crashpad_is_win) { + cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union + } +} + if (crashpad_is_linux) { crashpad_fuzzer_test("elf_image_reader_fuzzer") { sources = [ "elf/elf_image_reader_fuzzer.cc" ] @@ -406,6 +426,7 @@ source_set("snapshot_test") { ":test_support", "../client", "../compat", + "../minidump:format", "../test", "../third_party/gtest:gtest", "../third_party/mini_chromium:base", diff --git a/snapshot/crashpad_info_client_options.cc b/snapshot/crashpad_info_client_options.cc index fe3b0b38..3a88a4c0 100644 --- a/snapshot/crashpad_info_client_options.cc +++ b/snapshot/crashpad_info_client_options.cc @@ -15,7 +15,6 @@ #include "snapshot/crashpad_info_client_options.h" #include "base/logging.h" -#include "client/crashpad_info.h" namespace crashpad { diff --git a/snapshot/ios/module_snapshot_ios.h b/snapshot/ios/module_snapshot_ios.h index 7d0bbdc8..505c08f8 100644 --- a/snapshot/ios/module_snapshot_ios.h +++ b/snapshot/ios/module_snapshot_ios.h @@ -24,7 +24,6 @@ #include <vector> #include "base/macros.h" -#include "client/crashpad_info.h" #include "snapshot/crashpad_info_client_options.h" #include "snapshot/module_snapshot.h" #include "util/misc/initialization_state_dcheck.h" diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 4111c582..56d426ab 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -82,7 +82,6 @@ if (crashpad_is_in_fuchsia) { "$sdk_pkg_path/fidl_base/builder.cc", "$sdk_pkg_path/fidl_base/decoding.cc", "$sdk_pkg_path/fidl_base/encoding.cc", - "$sdk_pkg_path/fidl_base/envelope_frames.h", "$sdk_pkg_path/fidl_base/formatting.cc", "$sdk_pkg_path/fidl_base/linearizing.cc", "$sdk_pkg_path/fidl_base/message.cc", @@ -91,9 +90,7 @@ if (crashpad_is_in_fuchsia) { "$sdk_pkg_path/fidl_base/transformer.cc", "$sdk_pkg_path/fidl_base/txn_header.c", "$sdk_pkg_path/fidl_base/validating.cc", - "$sdk_pkg_path/fidl_base/visitor.h", "$sdk_pkg_path/fidl_base/walker.cc", - "$sdk_pkg_path/fidl_base/walker.h", ] public_configs = [ ":fidl_config" ] diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn index 1723c11d..e5a2ad38 100644 --- a/third_party/zlib/BUILD.gn +++ b/third_party/zlib/BUILD.gn @@ -71,9 +71,9 @@ if (zlib_source == "external") { "zlib/uncompr.c", "zlib/zconf.h", "zlib/zlib.h", - "zlib/zlib_crashpad.h", "zlib/zutil.c", "zlib/zutil.h", + "zlib_crashpad.h", ] cflags = [] diff --git a/util/win/exception_handler_server.cc b/util/win/exception_handler_server.cc index 2593ff2d..c841f7bc 100644 --- a/util/win/exception_handler_server.cc +++ b/util/win/exception_handler_server.cc @@ -26,9 +26,6 @@ #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "minidump/minidump_file_writer.h" -#include "snapshot/crashpad_info_client_options.h" -#include "snapshot/win/process_snapshot_win.h" #include "util/file/file_writer.h" #include "util/misc/tri_state.h" #include "util/misc/uuid.h" From 3c44556cf11e71739abe36f477ce843a10b4de4c Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 13 Apr 2020 20:31:43 -0400 Subject: [PATCH 374/401] Replace ScopedClearErrno with ScopedClearLastError Includes: Update mini_chromium to bbf1307928bb7a9d1eda6be576283c8093b2775b bbf1307928bb Replace ScopedClearErrno with ScopedClearLastError Change-Id: I8eabb5f62a21c5b30c5b07face2a6afcf10bb82b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2145829 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- snapshot/mac/system_snapshot_mac.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index b4f2ad26..62e2cccb 100644 --- a/DEPS +++ b/DEPS @@ -42,7 +42,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '731e08f0695801347a26d2b204d5c18f51c98282', + 'bbf1307928bb7a9d1eda6be576283c8093b2775b', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/snapshot/mac/system_snapshot_mac.cc b/snapshot/mac/system_snapshot_mac.cc index 586aabea..5410be08 100644 --- a/snapshot/mac/system_snapshot_mac.cc +++ b/snapshot/mac/system_snapshot_mac.cc @@ -23,7 +23,7 @@ #include <algorithm> #include "base/logging.h" -#include "base/scoped_clear_errno.h" +#include "base/scoped_clear_last_error.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "snapshot/cpu_context.h" @@ -359,7 +359,7 @@ bool SystemSnapshotMac::NXEnabled() const { #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14 const bool nx_always_enabled = true; #else // DT >= 10.14 - base::ScopedClearErrno reset_errno; + base::ScopedClearLastError reset_errno; const bool nx_always_enabled = MacOSXMinorVersion() >= 14; #endif // DT >= 10.14 if (nx_always_enabled) { From e5dbfa336351cf781d46dfedae8e1fa441440f15 Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Mon, 13 Apr 2020 18:54:55 -0700 Subject: [PATCH 375/401] Disable fuzzing without use_fuzzing_engine Effectively upstreams https://chromium-review.googlesource.com/c/chromium/src/+/1775756 Change-Id: I112eddd9e5f22790a50bf7b340cf9202eeceebc3 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2148373 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- build/crashpad_fuzzer_test.gni | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/crashpad_fuzzer_test.gni b/build/crashpad_fuzzer_test.gni index ef4b0d82..cc709b0d 100644 --- a/build/crashpad_fuzzer_test.gni +++ b/build/crashpad_fuzzer_test.gni @@ -44,7 +44,7 @@ template("crashpad_fuzzer_test") { if (defined(invoker.seed_corpus)) { not_needed(invoker, [ "seed_corpus" ]) } - } else if (crashpad_is_in_chromium) { + } else if (crashpad_is_in_chromium && use_fuzzing_engine) { # Append "crashpad_" to the beginning of the fuzzer's name to make it easier # in Chromium to recognize where fuzzer came from. forward_variables_from(invoker, "*") From de43cd37232ebcb9764dcd4493dcf263b4a81d23 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Tue, 14 Apr 2020 10:13:14 -0400 Subject: [PATCH 376/401] Fix Chromium Roll. - Fix -Wundeclared-selector in Chromium roll. - Convert TEST to TEST_F in crashpad_client_ios_test.mm Also rolls mini_chromim 731e08f06..641fcf9bb (3 commits) 2020-04-14 mark Mark static const class/struct members as constexpr 2020-04-09 justincohen Add PlatformTest to mini_chromium. 2020-04-09 jperaza Replace ScopedClearErrno with ScopedClearLastError Change-Id: Ib8ac742eb97359be47e1ff01ae6f10518761a302 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2144452 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- client/crashpad_client_ios_test.mm | 12 ++++++++---- test/ios/host/application_delegate.mm | 3 +++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/DEPS b/DEPS index 62e2cccb..b38c9b6a 100644 --- a/DEPS +++ b/DEPS @@ -42,7 +42,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - 'bbf1307928bb7a9d1eda6be576283c8093b2775b', + '641fcf9bbc1277e8153ac7e86d5b8f9340b1bfdd', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', diff --git a/client/crashpad_client_ios_test.mm b/client/crashpad_client_ios_test.mm index 357a7650..e07a1073 100644 --- a/client/crashpad_client_ios_test.mm +++ b/client/crashpad_client_ios_test.mm @@ -15,16 +15,20 @@ #include "client/crashpad_client.h" #import <Foundation/Foundation.h> + #include <vector> #include "gtest/gtest.h" +#include "testing/platform_test.h" namespace crashpad { namespace test { namespace { +using CrashpadIOSClient = PlatformTest; + // TODO(justincohen): This is a placeholder. -TEST(CrashpadIOSClient, DumpWithoutCrash) { +TEST_F(CrashpadIOSClient, DumpWithoutCrash) { CrashpadClient client; client.StartCrashpadInProcessHandler(); client.DumpWithoutCrash(); @@ -34,7 +38,7 @@ TEST(CrashpadIOSClient, DumpWithoutCrash) { // it's sometimes easier and faster to run as a gtest. However, there's no // way to correctly run this as a gtest. Leave the test here, disabled, for use // during development only. -TEST(CrashpadIOSClient, DISABLED_ThrowNSException) { +TEST_F(CrashpadIOSClient, DISABLED_ThrowNSException) { CrashpadClient client; client.StartCrashpadInProcessHandler(); [NSException raise:@"GtestNSException" format:@"ThrowException"]; @@ -44,10 +48,10 @@ TEST(CrashpadIOSClient, DISABLED_ThrowNSException) { // it's sometimes easier and faster to run as a gtest. However, there's no // way to correctly run this as a gtest. Leave the test here, disabled, for use // during development only. -TEST(CrashpadIOSClient, DISABLED_ThrowException) { +TEST_F(CrashpadIOSClient, DISABLED_ThrowException) { CrashpadClient client; client.StartCrashpadInProcessHandler(); - std::vector<int> empty_vector = {}; + std::vector<int> empty_vector; empty_vector.at(42); } diff --git a/test/ios/host/application_delegate.mm b/test/ios/host/application_delegate.mm index f8320857..c74229a8 100644 --- a/test/ios/host/application_delegate.mm +++ b/test/ios/host/application_delegate.mm @@ -102,7 +102,10 @@ } - (void)crashUnreocgnizedSelectorAfterDelay { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" [self performSelector:@selector(does_not_exist) withObject:nil afterDelay:1]; +#pragma clang diagnostic pop } - (void)recurse { From b49dcdc48fd95aacb0f202842fe54753cc5cdcb7 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 14 Apr 2020 09:59:21 -0400 Subject: [PATCH 377/401] Mark static const class/struct members as constexpr cl/306269985 Change-Id: I3e6b7021d24260aa1abfad32d30ee0a9289fa3ff Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2148677 Reviewed-by: Robert Sesek <rsesek@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- client/settings.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/settings.cc b/client/settings.cc index db9dface..0aa525f1 100644 --- a/client/settings.cc +++ b/client/settings.cc @@ -85,8 +85,8 @@ void ScopedLockedFileHandleTraits::Free(FileHandle handle) { #endif // OS_FUCHSIA struct Settings::Data { - static const uint32_t kSettingsMagic = 'CPds'; - static const uint32_t kSettingsVersion = 1; + static constexpr uint32_t kSettingsMagic = 'CPds'; + static constexpr uint32_t kSettingsVersion = 1; enum Options : uint32_t { kUploadsEnabled = 1 << 0, From 24b4105d000a42a81f744252862626d8b69efb8d Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 13 Apr 2020 14:54:33 -0400 Subject: [PATCH 378/401] =?UTF-8?q?fuchsia:=20Fix=20clang=20path=20for=20m?= =?UTF-8?q?acOS=E2=86=92Fuchsia=20cross-development?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was a goof from 3af81d7012e4. Change-Id: I09b2e387511f661413f33c1873ad1a9036b0bd09 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2144437 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index b38c9b6a..0c5da0a6 100644 --- a/DEPS +++ b/DEPS @@ -61,7 +61,7 @@ deps = { 'condition': 'checkout_linux and pull_linux_clang', 'dep_type': 'cipd' }, - 'crashpad/third_party/linux/clang/mac-amd64': { + 'crashpad/third_party/fuchsia/clang/mac-amd64': { 'packages': [ { 'package': 'fuchsia/clang/mac-amd64', From dc9176b063bee1d29885f70768946b10af1aae56 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 15 Apr 2020 10:33:31 -0400 Subject: [PATCH 379/401] =?UTF-8?q?iOS:=20=E2=80=9Cnamespace=E2=80=9D?= =?UTF-8?q?=C2=A0Objective-C=20test=20classes=20by=20prefixing=20with=20CP?= =?UTF-8?q?Test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re: https://chromium-review.googlesource.com/c/2028183/4/test/ios/crash_type_xctest.mm#13 We previously discussed using the CP prefix for Objective-C class and protocol names, and CPTest for those restricted to tests. This is intended to parallel our C++ code’s use of the crashpad and crashpad::test namespaces, but with name prefixing because Objective-C doesn’t support any other form of namespacing. These class names are changed: ApplicationDelegate→CPTestApplicationDelegate CrashViewController→CPTestCrashViewController CrashpadUnitTestDelegate→CPTestUnitTestApplicationDelegate Filenames and #include guards are also adjusted to match. This also has include-what-you-use fixes and more modern pointer handling in CPTestSharedObject, which was already named correctly. Bug: crashpad:31 Change-Id: I3645ee830a30eccb594d679e0d52ba1a2dd1225d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2144453 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Justin Cohen <justincohen@chromium.org> --- test/ios/google_test_setup.mm | 9 ++++---- test/ios/host/BUILD.gn | 8 +++---- ...roller.h => cptest_application_delegate.h} | 8 +++---- ...gate.mm => cptest_application_delegate.mm} | 21 ++++++++++++------- ...egate.h => cptest_crash_view_controller.h} | 8 +++---- ...ler.mm => cptest_crash_view_controller.mm} | 4 ++-- test/ios/host/main.mm | 4 ++-- 7 files changed, 35 insertions(+), 27 deletions(-) rename test/ios/host/{crash_view_controller.h => cptest_application_delegate.h} (71%) rename test/ios/host/{application_delegate.mm => cptest_application_delegate.mm} (87%) rename test/ios/host/{application_delegate.h => cptest_crash_view_controller.h} (72%) rename test/ios/host/{crash_view_controller.mm => cptest_crash_view_controller.mm} (90%) diff --git a/test/ios/google_test_setup.mm b/test/ios/google_test_setup.mm index b2211903..109c4b68 100644 --- a/test/ios/google_test_setup.mm +++ b/test/ios/google_test_setup.mm @@ -53,12 +53,13 @@ void RegisterTestEndListener() { } // namespace -@interface CrashpadUnitTestDelegate : NSObject <CPTestGoogleTestRunnerDelegate> +@interface CPTestUnitTestApplicationDelegate + : NSObject <CPTestGoogleTestRunnerDelegate> @property(nonatomic, readwrite, strong) UIWindow* window; - (void)runTests; @end -@implementation CrashpadUnitTestDelegate +@implementation CPTestUnitTestApplicationDelegate - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { @@ -123,8 +124,8 @@ namespace test { void IOSLaunchApplicationAndRunTests(int argc, char* argv[]) { @autoreleasepool { - int exit_status = - UIApplicationMain(argc, argv, nil, @"CrashpadUnitTestDelegate"); + int exit_status = UIApplicationMain( + argc, argv, nil, @"CPTestUnitTestApplicationDelegate"); exit(exit_status); } } diff --git a/test/ios/host/BUILD.gn b/test/ios/host/BUILD.gn index e0d289d4..cd6995a9 100644 --- a/test/ios/host/BUILD.gn +++ b/test/ios/host/BUILD.gn @@ -31,10 +31,10 @@ source_set("app_shared_sources") { static_library("app_host_sources") { testonly = true sources = [ - "application_delegate.h", - "application_delegate.mm", - "crash_view_controller.h", - "crash_view_controller.mm", + "cptest_application_delegate.h", + "cptest_application_delegate.mm", + "cptest_crash_view_controller.h", + "cptest_crash_view_controller.mm", "main.mm", ] configs += [ "../../..:crashpad_config" ] diff --git a/test/ios/host/crash_view_controller.h b/test/ios/host/cptest_application_delegate.h similarity index 71% rename from test/ios/host/crash_view_controller.h rename to test/ios/host/cptest_application_delegate.h index fdbdfc1a..ca835f12 100644 --- a/test/ios/host/crash_view_controller.h +++ b/test/ios/host/cptest_application_delegate.h @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CRASHPAD_TEST_IOS_HOST_CRASH_VIEW_CONTROLLER_H_ -#define CRASHPAD_TEST_IOS_HOST_CRASH_VIEW_CONTROLLER_H_ +#ifndef CRASHPAD_TEST_IOS_HOST_CPTEST_APPLICATION_DELEGATE_H_ +#define CRASHPAD_TEST_IOS_HOST_CPTEST_APPLICATION_DELEGATE_H_ #import <UIKit/UIKit.h> -@interface CrashViewController : UIViewController +@interface CPTestApplicationDelegate : UIResponder <UIApplicationDelegate> @end -#endif // CRASHPAD_TEST_IOS_HOST_CRASH_VIEW_CONTROLLER_H_ +#endif // CRASHPAD_TEST_IOS_HOST_CPTEST_APPLICATION_DELEGATE_H_ diff --git a/test/ios/host/application_delegate.mm b/test/ios/host/cptest_application_delegate.mm similarity index 87% rename from test/ios/host/application_delegate.mm rename to test/ios/host/cptest_application_delegate.mm index c74229a8..80baf8b3 100644 --- a/test/ios/host/application_delegate.mm +++ b/test/ios/host/cptest_application_delegate.mm @@ -12,23 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "test/ios/host/application_delegate.h" +#import "test/ios/host/cptest_application_delegate.h" #include <dispatch/dispatch.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> #include <vector> #import "Service/Sources/EDOHostNamingService.h" #import "Service/Sources/EDOHostService.h" #include "client/crashpad_client.h" +#import "test/ios/host/cptest_crash_view_controller.h" #import "test/ios/host/cptest_shared_object.h" -#import "test/ios/host/crash_view_controller.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -@implementation ApplicationDelegate +@implementation CPTestApplicationDelegate + @synthesize window = _window; - (BOOL)application:(UIApplication*)application @@ -41,7 +46,8 @@ [self.window makeKeyAndVisible]; self.window.backgroundColor = UIColor.greenColor; - CrashViewController* controller = [[CrashViewController alloc] init]; + CPTestCrashViewController* controller = + [[CPTestCrashViewController alloc] init]; self.window.rootViewController = controller; // Start up EDO. @@ -54,12 +60,13 @@ @end @implementation CPTestSharedObject + - (NSString*)testEDO { return @"crashpad"; } - (void)crashBadAccess { - strcpy(0, "bla"); + strcpy(nullptr, "bla"); } - (void)crashKillAbort { @@ -67,8 +74,8 @@ } - (void)crashSegv { - long zero = 0; - *(long*)zero = 0xC045004d; + long* zero = nullptr; + *zero = 0xc045004d; } - (void)crashTrap { diff --git a/test/ios/host/application_delegate.h b/test/ios/host/cptest_crash_view_controller.h similarity index 72% rename from test/ios/host/application_delegate.h rename to test/ios/host/cptest_crash_view_controller.h index 3405e7a8..2a41e129 100644 --- a/test/ios/host/application_delegate.h +++ b/test/ios/host/cptest_crash_view_controller.h @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CRASHPAD_TEST_IOS_HOST_APPLICATION_DELEGATE_H_ -#define CRASHPAD_TEST_IOS_HOST_APPLICATION_DELEGATE_H_ +#ifndef CRASHPAD_TEST_IOS_HOST_CPTEST_CRASH_VIEW_CONTROLLER_H_ +#define CRASHPAD_TEST_IOS_HOST_CPTEST_CRASH_VIEW_CONTROLLER_H_ #import <UIKit/UIKit.h> -@interface ApplicationDelegate : UIResponder <UIApplicationDelegate> +@interface CPTestCrashViewController : UIViewController @end -#endif // CRASHPAD_TEST_IOS_HOST_APPLICATION_DELEGATE_H_ +#endif // CRASHPAD_TEST_IOS_HOST_CPTEST_CRASH_VIEW_CONTROLLER_H_ diff --git a/test/ios/host/crash_view_controller.mm b/test/ios/host/cptest_crash_view_controller.mm similarity index 90% rename from test/ios/host/crash_view_controller.mm rename to test/ios/host/cptest_crash_view_controller.mm index f8c05f76..90f92dae 100644 --- a/test/ios/host/crash_view_controller.mm +++ b/test/ios/host/cptest_crash_view_controller.mm @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "test/ios/host/crash_view_controller.h" +#import "test/ios/host/cptest_crash_view_controller.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -@implementation CrashViewController +@implementation CPTestCrashViewController - (void)loadView { self.view = [[UIView alloc] init]; diff --git a/test/ios/host/main.mm b/test/ios/host/main.mm index 932cd897..a0ae5c46 100644 --- a/test/ios/host/main.mm +++ b/test/ios/host/main.mm @@ -14,7 +14,7 @@ #import <UIKit/UIKit.h> -#import "test/ios/host/application_delegate.h" +#import "test/ios/host/cptest_application_delegate.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -24,7 +24,7 @@ int main(int argc, char* argv[]) { NSString* appDelegateClassName; @autoreleasepool { // Setup code that might create autoreleased objects goes here. - appDelegateClassName = NSStringFromClass([ApplicationDelegate class]); + appDelegateClassName = NSStringFromClass([CPTestApplicationDelegate class]); } return UIApplicationMain(argc, argv, nil, appDelegateClassName); } From 7fa69e7e4383a265d8b46da1001783790197de8a Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 15 Apr 2020 12:37:32 -0400 Subject: [PATCH 380/401] win: Remove disabled and flaky end-to-end tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The “and not memory after range” follow-up to the “extra memory range captured” test is very flaky in debug builds (https://ci.chromium.org/p/crashpad/builders/ci/crashpad_win_dbg/388), and occasionally flaky in release builds too (https://ci.chromium.org/p/crashpad/builders/ci/crashpad_win_rel/363). As with the already-disabled “extra memory removal” test, it’s likely that Crashpad is discovering a pointer that references the memory immediately beyond the intended range, and capturing that too. Unless the environment is very tightly controlled, it’s difficult to prevent valid memory from being pointed to, and thus to guarantee that Crashpad won’t capture a particular block of memory. These are probably never going to be fixed. The flaky tests are removed. Bug: crashpad:101 Change-Id: I629ed8ce3c901507689218baaa102d8737db3f5b Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2150055 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- snapshot/win/end_to_end_test.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/snapshot/win/end_to_end_test.py b/snapshot/win/end_to_end_test.py index fd602fbc..8823785f 100755 --- a/snapshot/win/end_to_end_test.py +++ b/snapshot/win/end_to_end_test.py @@ -363,23 +363,6 @@ def RunTests(cdb_path, 'L8') out.Check(r'0000655e 0000656b 00006578 00006585', 'extra memory range captured') - out.Check(r'\?\?\?\?\?\?\?\? \?\?\?\?\?\?\?\? ' - r'\?\?\?\?\?\?\?\? \?\?\?\?\?\?\?\?', - ' and not memory after range') - - if False: - # TODO(scottmg): This is flakily capturing too much memory in Debug builds, - # possibly because a stale pointer is being captured via the stack. - # See: https://bugs.chromium.org/p/crashpad/issues/detail?id=101. - out = CdbRun(cdb_path, dump_path, - 'dd poi(crashy_program!crashpad::g_extra_memory_not_saved)' - '+0x1f30 L4') - # We save only the pointer, not the pointed-to data. If the pointer itself - # wasn't saved, then we won't get any memory printed, so here we're - # confirming the pointer was saved but the memory wasn't. - out.Check(r'\?\?\?\?\?\?\?\? \?\?\?\?\?\?\?\? ' - r'\?\?\?\?\?\?\?\? \?\?\?\?\?\?\?\?', - 'extra memory removal') out = CdbRun(cdb_path, dump_path, '.dumpdebug') out.Check(r'type \?\?\? \(333333\), size 00001000', From ea4af71c2ac7a2daa50e4d22bc48270b1a66c83a Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Wed, 15 Apr 2020 17:46:45 -0400 Subject: [PATCH 381/401] Add another iOS library path sinkhole. Add another sinkhole for _UIGestureEnvironmentUpdate. Bug: crashpad:31 Change-Id: Ic4a424da034249295b6e45f8fe0860a4d4696b93 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2145017 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Justin Cohen <justincohen@chromium.org> Reviewed-by: Robert Sesek <rsesek@chromium.org> --- BUILD.gn | 8 +-- test/ios/crash_type_xctest.mm | 15 +++++ test/ios/host/cptest_crash_view_controller.mm | 34 ++++++++++++ util/BUILD.gn | 29 ++++++++-- util/ios/exception_processor.mm | 55 +++++++++++++++++-- util/ios/exception_processor_test.mm | 41 ++++++++++++++ 6 files changed, 167 insertions(+), 15 deletions(-) create mode 100644 util/ios/exception_processor_test.mm diff --git a/BUILD.gn b/BUILD.gn index 17c380e5..0b16a6df 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -45,7 +45,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "handler:handler_test", "minidump:minidump_test", "snapshot:snapshot_test", - "util:util_test", ] } if (crashpad_is_in_fuchsia) { @@ -63,9 +62,7 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "util/net/testdata/binary_http_body.dat", ] - outputs = [ - "$root_out_dir/crashpad_test_data/{{source}}", - ] + outputs = [ "$root_out_dir/crashpad_test_data/{{source}}" ] } deps += [ ":crashpad_test_data" ] @@ -222,9 +219,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "test:gmock_main", "util:util_test", ] - if (crashpad_is_ios) { - deps -= [ "util:util_test" ] - } } } diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm index 5369e3cf..45291243 100644 --- a/test/ios/crash_type_xctest.mm +++ b/test/ios/crash_type_xctest.mm @@ -193,6 +193,21 @@ XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); } +- (void)testCatchUIGestureEnvironmentNSException { + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); + + // Tap the button with the string UIGestureEnvironmentException. + [_app.buttons[@"UIGestureEnvironmentException"] tap]; + + // Confirm the app is not running. + XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]); + XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning); + + // TODO: Query the app for crash data + [_app launch]; + XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); +} + - (void)testCatchNSException { XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground); diff --git a/test/ios/host/cptest_crash_view_controller.mm b/test/ios/host/cptest_crash_view_controller.mm index 90f92dae..8e49b027 100644 --- a/test/ios/host/cptest_crash_view_controller.mm +++ b/test/ios/host/cptest_crash_view_controller.mm @@ -22,6 +22,40 @@ - (void)loadView { self.view = [[UIView alloc] init]; + + UIStackView* buttonStack = [[UIStackView alloc] init]; + buttonStack.axis = UILayoutConstraintAxisVertical; + buttonStack.spacing = 6; + + UIButton* button = [UIButton new]; + [button setTitle:@"UIGestureEnvironmentException" + forState:UIControlStateNormal]; + UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] + initWithTarget:self + action:@selector(throwUIGestureEnvironmentException)]; + [button addGestureRecognizer:tapGesture]; + [button setTranslatesAutoresizingMaskIntoConstraints:NO]; + [button.widthAnchor constraintEqualToConstant:16.0].active = YES; + [button.heightAnchor constraintEqualToConstant:16.0].active = YES; + + [buttonStack addArrangedSubview:button]; + + [self.view addSubview:buttonStack]; + + [buttonStack setTranslatesAutoresizingMaskIntoConstraints:NO]; + + [NSLayoutConstraint activateConstraints:@[ + [buttonStack.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + [buttonStack.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [buttonStack.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [buttonStack.trailingAnchor + constraintEqualToAnchor:self.view.trailingAnchor], + ]]; +} + +- (void)throwUIGestureEnvironmentException { + NSArray* empty_array = @[]; + [empty_array objectAtIndex:42]; } - (void)viewDidLoad { diff --git a/util/BUILD.gn b/util/BUILD.gn index 18cc112f..183a0a82 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -548,7 +548,7 @@ static_library("util") { configs += [ "..:disable_ubsan" ] } -if (!crashpad_is_android) { +if (!crashpad_is_android && !crashpad_is_ios) { crashpad_executable("http_transport_test_server") { testonly = true sources = [ "net/http_transport_test_server.cc" ] @@ -639,13 +639,13 @@ source_set("util_test") { "thread/worker_thread_test.cc", ] - if (!crashpad_is_android) { + if (!crashpad_is_android && !crashpad_is_ios) { # Android requires an HTTPTransport implementation. sources += [ "net/http_transport_test.cc" ] } if (crashpad_is_posix || crashpad_is_fuchsia) { - if (!crashpad_is_fuchsia) { + if (!crashpad_is_fuchsia && !crashpad_is_ios) { sources += [ "posix/process_info_test.cc", "posix/signals_test.cc", @@ -680,6 +680,27 @@ source_set("util_test") { ] } + if (crashpad_is_ios) { + sources += [ "ios/exception_processor_test.mm" ] + + sources -= [ + "file/directory_reader_test.cc", + "file/file_io_test.cc", + "file/filesystem_test.cc", + "misc/capture_context_test.cc", + "misc/clock_test.cc", + "misc/paths_test.cc", + "net/http_body_test.cc", + "net/http_multipart_builder_test.cc", + "process/process_memory_range_test.cc", + "process/process_memory_test.cc", + "stream/file_encoder_test.cc", + "synchronization/semaphore_test.cc", + "thread/thread_test.cc", + "thread/worker_thread_test.cc", + ] + } + if (crashpad_is_linux || crashpad_is_android) { sources += [ "linux/auxiliary_vector_test.cc", @@ -739,7 +760,7 @@ source_set("util_test") { deps += [ "../third_party/lss" ] } - if (!crashpad_is_android) { + if (!crashpad_is_android && !crashpad_is_ios) { data_deps = [ ":http_transport_test_server" ] if (crashpad_use_boringssl_for_http_transport_socket) { diff --git a/util/ios/exception_processor.mm b/util/ios/exception_processor.mm index 818d4980..f767fb14 100644 --- a/util/ios/exception_processor.mm +++ b/util/ios/exception_processor.mm @@ -20,6 +20,7 @@ #include <dlfcn.h> #include <libunwind.h> #include <mach-o/loader.h> +#include <objc/message.h> #include <objc/objc-exception.h> #include <objc/objc.h> #include <objc/runtime.h> @@ -109,6 +110,14 @@ bool ModulePathMatchesSinkhole(const char* path, const char* sinkhole) { #endif } +int LoggingUnwStep(unw_cursor_t* cursor) { + int rv = unw_step(cursor); + if (rv < 0) { + LOG(ERROR) << "unw_step: " << rv; + } + return rv; +} + id ObjcExceptionPreprocessor(id exception) { // Unwind the stack looking for any exception handlers. If an exception // handler is encountered, test to see if it is a function known to catch- @@ -152,7 +161,7 @@ id ObjcExceptionPreprocessor(id exception) { exception_header->unwindHeader.exception_class = kOurExceptionClass; bool handler_found = false; - while (unw_step(&cursor) > 0) { + while (LoggingUnwStep(&cursor) > 0) { unw_proc_info_t frame_info; if (unw_get_proc_info(&cursor, &frame_info) != UNW_ESUCCESS) { continue; @@ -226,14 +235,14 @@ id ObjcExceptionPreprocessor(id exception) { // Everything in this library is a sinkhole, specifically // _dispatch_client_callout. Both are needed here depending on whether // the debugger is attached (introspection only appears when a simulator - // is attached to a debugger. - // only). + // is attached to a debugger). "/usr/lib/system/introspection/libdispatch.dylib", "/usr/lib/system/libdispatch.dylib", // __CFRunLoopDoTimers and __CFRunLoopRun are sinkholes. Consider also // checking that a few frames up is CFRunLoopRunSpecific(). - "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"}; + "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", + }; Dl_info dl_info; if (dladdr(reinterpret_cast<const void*>(frame_info.start_ip), &dl_info) != @@ -245,6 +254,44 @@ id ObjcExceptionPreprocessor(id exception) { } } + // Some <redacted> sinkholes are harder to find. _UIGestureEnvironmentUpdate + // in UIKitCore is an example. UIKitCore can't be added to + // kExceptionLibraryPathSinkholes because it uses Objective-C exceptions + // internally and also has has non-sinkhole handlers. Since + // _UIGestureEnvironmentUpdate is always called from + // -[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:], + // inspect the caller frame info to match the sinkhole. + constexpr const char* kUIKitCorePath = + "/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore"; + if (ModulePathMatchesSinkhole(dl_info.dli_fname, kUIKitCorePath)) { + unw_proc_info_t caller_frame_info; + if (LoggingUnwStep(&cursor) > 0 && + unw_get_proc_info(&cursor, &caller_frame_info) == UNW_ESUCCESS) { + static IMP uigesture_deliver_event_imp = [] { + IMP imp = class_getMethodImplementation( + NSClassFromString(@"UIGestureEnvironment"), + NSSelectorFromString( + @"_deliverEvent:toGestureRecognizers:usingBlock:")); + + // From 10.15.0 objc4-779.1/runtime/objc-class.mm + // class_getMethodImplementation returns nil or _objc_msgForward on + // failure. + if (!imp || imp == _objc_msgForward) { + LOG(WARNING) << "Unable to find -[UIGestureEnvironment " + "_deliverEvent:toGestureRecognizers:usingBlock:]"; + return reinterpret_cast<IMP>(NULL); + } + return imp; + }(); + + if (uigesture_deliver_event_imp == + reinterpret_cast<IMP>(caller_frame_info.start_ip)) { + TerminatingFromUncaughtNSException(exception, + "_UIGestureEnvironmentUpdate"); + } + } + } + handler_found = true; break; diff --git a/util/ios/exception_processor_test.mm b/util/ios/exception_processor_test.mm new file mode 100644 index 00000000..c9aa7169 --- /dev/null +++ b/util/ios/exception_processor_test.mm @@ -0,0 +1,41 @@ +// 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. + +#import <Foundation/Foundation.h> +#include <objc/message.h> +#include <objc/runtime.h> + +#include "gtest/gtest.h" +#include "testing/platform_test.h" + +namespace crashpad { +namespace test { +namespace { + +using IOSExceptionProcessor = PlatformTest; + +TEST_F(IOSExceptionProcessor, SelectorExists) { + IMP uigesture_deliver_event_imp = class_getMethodImplementation( + NSClassFromString(@"UIGestureEnvironment"), + NSSelectorFromString(@"_deliverEvent:toGestureRecognizers:usingBlock:")); + + // From 10.15.0 objc4-779.1/runtime/objc-class.mm + // class_getMethodImplementation returns nil or _objc_msgForward on failure. + ASSERT_TRUE(uigesture_deliver_event_imp); + ASSERT_NE(uigesture_deliver_event_imp, _objc_msgForward); +} + +} // namespace +} // namespace test +} // namespace crashpad From 122a400d7b585194b557c89d4afb859c25e916de Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 17 Apr 2020 10:37:15 -0400 Subject: [PATCH 382/401] ios: Enable (and test!) more of util and test This builds some code in the util and test libraries on iOS that was previously excluded. It also enables tests for this code, and other tests that it was possible to enable either previously or as a result of this change. Previously, crashpad_util_test ran 178 tests from 46 test suites, and crashpad_test_test ran 2 tests from 2 test suites. Now, crashpad_util_test runs 284 tests from 62 test suites, and crashpad_test_test runs 6 tests from 4 test suites. The related .gn files also suffered through a slight cleanup. Bug: crashpad:31 Change-Id: I84cdda5631f0ea4888ada902a8462776ac46fd2a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2154526 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- test/BUILD.gn | 74 +++++++++++++++++++--------------------------- test/test_paths.cc | 16 ++++++---- util/BUILD.gn | 72 +++++++++++++++++++++++++++----------------- 3 files changed, 85 insertions(+), 77 deletions(-) diff --git a/test/BUILD.gn b/test/BUILD.gn index bfbdd513..32dc298f 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -43,29 +43,6 @@ static_library("test") { "test_paths.h", ] - if (crashpad_is_ios) { - sources -= [ - "errors.cc", - "errors.h", - "file.cc", - "file.h", - "filesystem.cc", - "filesystem.h", - "multiprocess.h", - "multiprocess_exec.cc", - "multiprocess_exec.h", - "process_type.cc", - "process_type.h", - "scoped_guarded_page.h", - "scoped_module_handle.cc", - "scoped_module_handle.h", - "scoped_temp_dir.cc", - "scoped_temp_dir.h", - "test_paths.cc", - "test_paths.h", - ] - } - if (crashpad_is_posix || crashpad_is_fuchsia) { sources += [ "scoped_guarded_page_posix.cc", @@ -93,6 +70,14 @@ static_library("test") { ] } + if (crashpad_is_ios) { + sources -= [ + "multiprocess.h", + "multiprocess_exec.cc", + "multiprocess_exec.h", + ] + } + if (crashpad_is_linux || crashpad_is_android) { set_sources_assignment_filter([]) sources += [ @@ -139,13 +124,6 @@ static_library("test") { "../util", ] - if (crashpad_is_ios) { - deps -= [ - "../compat", - "../util", - ] - } - if (crashpad_is_mac) { libs = [ "bsm" ] deps += [ @@ -154,6 +132,10 @@ static_library("test") { ] } + if (crashpad_is_ios) { + deps += [ ":test_bundle_data" ] + } + if (crashpad_is_win) { libs = [ "shell32.lib" ] } @@ -166,6 +148,17 @@ static_library("test") { } } +if (crashpad_is_ios) { + bundle_data("test_bundle_data") { + testonly = true + + sources = [ "test_paths_test_data_root.txt" ] + + outputs = [ "{{bundle_resources_dir}}/crashpad_test_data/" + + "{{source_root_relative_dir}}/{{source_file_part}}" ] + } +} + source_set("test_test") { testonly = true @@ -178,15 +171,6 @@ source_set("test_test") { "test_paths_test.cc", ] - if (crashpad_is_ios) { - sources -= [ - "multiprocess_exec_test.cc", - "scoped_guarded_page_test.cc", - "scoped_temp_dir_test.cc", - "test_paths_test.cc", - ] - } - # 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 && !crashpad_is_ios) { @@ -197,6 +181,13 @@ source_set("test_test") { sources += [ "mac/mach_multiprocess_test.cc" ] } + if (crashpad_is_ios) { + sources -= [ + "multiprocess_exec_test.cc", + "scoped_guarded_page_test.cc", + ] + } + if (crashpad_is_win) { sources += [ "win/win_child_process_test.cc", @@ -216,11 +207,6 @@ source_set("test_test") { data_deps = [ ":crashpad_test_test_multiprocess_exec_test_child" ] if (crashpad_is_ios) { - deps -= [ - "../compat", - "../util", - ] - data_deps -= [ ":crashpad_test_test_multiprocess_exec_test_child" ] } } diff --git a/test/test_paths.cc b/test/test_paths.cc index dfe6c96b..475e2b01 100644 --- a/test/test_paths.cc +++ b/test/test_paths.cc @@ -46,7 +46,7 @@ base::FilePath TestDataRootInternal() { #if defined(OS_FUCHSIA) base::FilePath asset_path("/pkg/data"); if (!IsTestDataRoot(asset_path)) { - LOG(WARNING) << "Test data root seems invalid, continuing anyway"; + LOG(WARNING) << "test data root seems invalid, continuing anyway"; } return asset_path; #else // defined(OS_FUCHSIA) @@ -65,19 +65,23 @@ base::FilePath TestDataRootInternal() { return base::FilePath(environment_value); } - // In a standalone build, the test executable is usually at - // out/{Debug,Release} relative to the Crashpad root. base::FilePath executable_path; if (Paths::Executable(&executable_path)) { -#if defined(OS_ANDROID) +#if defined(OS_IOS) || defined(OS_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 +#else // OS_IOS || OS_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 +#endif // OS_IOS || OS_ANDROID if (IsTestDataRoot(candidate)) { return candidate; } diff --git a/util/BUILD.gn b/util/BUILD.gn index 183a0a82..7fe02f2b 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -244,14 +244,13 @@ static_library("util") { } } - if (crashpad_is_ios) { + if (crashpad_is_mac || crashpad_is_ios) { sources += [ - "ios/exception_processor.h", - "ios/exception_processor.mm", - "ios/ios_system_data_collector.h", - "ios/ios_system_data_collector.mm", "mac/xattr.cc", "mac/xattr.h", + "misc/clock_mac.cc", + "misc/paths_mac.cc", + "synchronization/semaphore_mac.cc", ] } @@ -264,8 +263,6 @@ static_library("util") { "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", @@ -298,13 +295,19 @@ static_library("util") { "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 (crashpad_is_ios) { + sources += [ + "ios/exception_processor.h", + "ios/exception_processor.mm", + "ios/ios_system_data_collector.h", + "ios/ios_system_data_collector.mm", ] } @@ -655,12 +658,15 @@ source_set("util_test") { sources += [ "posix/scoped_mmap_test.cc" ] } + if (crashpad_is_mac || crashpad_is_ios) { + sources += [ "mac/xattr_test.cc" ] + } + if (crashpad_is_mac) { sources += [ "mac/launchd_test.mm", "mac/mac_util_test.mm", "mac/service_management_test.mm", - "mac/xattr_test.cc", "mach/child_port_handshake_test.cc", "mach/child_port_server_test.cc", "mach/composite_mach_message_server_test.cc", @@ -684,20 +690,9 @@ source_set("util_test") { sources += [ "ios/exception_processor_test.mm" ] sources -= [ - "file/directory_reader_test.cc", - "file/file_io_test.cc", - "file/filesystem_test.cc", "misc/capture_context_test.cc", - "misc/clock_test.cc", - "misc/paths_test.cc", - "net/http_body_test.cc", - "net/http_multipart_builder_test.cc", "process/process_memory_range_test.cc", "process/process_memory_test.cc", - "stream/file_encoder_test.cc", - "synchronization/semaphore_test.cc", - "thread/thread_test.cc", - "thread/worker_thread_test.cc", ] } @@ -743,7 +738,12 @@ source_set("util_test") { } } - data = [ "net/testdata/" ] + data = [ + "net/testdata/ascii_http_body.txt", + "net/testdata/binary_http_body.dat", + "net/testdata/crashpad_util_test_cert.pem", + "net/testdata/crashpad_util_test_key.pem", + ] deps = [ ":util", @@ -756,10 +756,6 @@ source_set("util_test") { "../third_party/zlib", ] - if (crashpad_is_android || crashpad_is_linux) { - deps += [ "../third_party/lss" ] - } - if (!crashpad_is_android && !crashpad_is_ios) { data_deps = [ ":http_transport_test_server" ] @@ -772,6 +768,14 @@ source_set("util_test") { libs = [ "Foundation.framework" ] } + if (crashpad_is_ios) { + deps += [ ":util_test_bundle_data" ] + } + + if (crashpad_is_android || crashpad_is_linux) { + deps += [ "../third_party/lss" ] + } + if (crashpad_is_win) { libs = [ "rpcrt4.lib", @@ -785,6 +789,20 @@ source_set("util_test") { } } +if (crashpad_is_ios) { + bundle_data("util_test_bundle_data") { + testonly = true + + sources = [ + "net/testdata/ascii_http_body.txt", + "net/testdata/binary_http_body.dat", + ] + + outputs = [ "{{bundle_resources_dir}}/crashpad_test_data/" + + "{{source_root_relative_dir}}/{{source_file_part}}" ] + } +} + if (crashpad_is_win) { crashpad_executable("crashpad_util_test_process_info_test_child") { testonly = true From ba24acb86ca66277cc5fc7311961825850b04570 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 17 Apr 2020 11:29:09 -0400 Subject: [PATCH 383/401] ios: Split bootstrap out from mach_extensions mach_extensions is sensible on iOS, but bootstrap is not available outside of macOS. To allow mach_extensions to be used cleanly on iOS, the bootstrap code is moved into its own macOS-specific file. Bug: crashpad:31 Change-Id: I7bf9d5194253b563954a1e55fbf67a16f686e8ff Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2154529 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- client/crashpad_client_mac.cc | 1 + handler/handler_main.cc | 2 +- handler/mac/crash_report_exception_handler.cc | 1 + test/BUILD.gn | 9 +- test/mac/exception_swallower.cc | 1 + test/mac/mach_errors.cc | 25 ---- test/mac/mach_errors.h | 23 +--- test/mac/mach_multiprocess.cc | 1 + tools/mac/catch_exception_tool.cc | 1 + tools/mac/exception_port_tool.cc | 1 + util/BUILD.gn | 13 ++- util/mach/bootstrap.cc | 109 ++++++++++++++++++ util/mach/bootstrap.h | 63 ++++++++++ util/mach/bootstrap_test.cc | 70 +++++++++++ util/mach/child_port_handshake.cc | 1 + util/mach/mach_extensions.cc | 107 +++-------------- util/mach/mach_extensions.h | 41 ------- util/mach/mach_extensions_test.cc | 57 +++------ 18 files changed, 299 insertions(+), 227 deletions(-) create mode 100644 util/mach/bootstrap.cc create mode 100644 util/mach/bootstrap.h create mode 100644 util/mach/bootstrap_test.cc diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc index 22bd538c..2fa8729b 100644 --- a/client/crashpad_client_mac.cc +++ b/client/crashpad_client_mac.cc @@ -26,6 +26,7 @@ #include "base/mac/mach_logging.h" #include "base/strings/stringprintf.h" #include "util/mac/mac_util.h" +#include "util/mach/bootstrap.h" #include "util/mach/child_port_handshake.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" diff --git a/handler/handler_main.cc b/handler/handler_main.cc index e0a262cd..69da0f61 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -74,8 +74,8 @@ #include "handler/mac/crash_report_exception_handler.h" #include "handler/mac/exception_handler_server.h" #include "handler/mac/file_limit_annotation.h" +#include "util/mach/bootstrap.h" #include "util/mach/child_port_handshake.h" -#include "util/mach/mach_extensions.h" #include "util/posix/close_stdio.h" #include "util/posix/signals.h" #elif defined(OS_WIN) diff --git a/handler/mac/crash_report_exception_handler.cc b/handler/mac/crash_report_exception_handler.cc index 9919e955..cccf1e94 100644 --- a/handler/mac/crash_report_exception_handler.cc +++ b/handler/mac/crash_report_exception_handler.cc @@ -28,6 +28,7 @@ #include "snapshot/crashpad_info_client_options.h" #include "snapshot/mac/process_snapshot_mac.h" #include "util/file/file_writer.h" +#include "util/mach/bootstrap.h" #include "util/mach/exc_client_variants.h" #include "util/mach/exception_behaviors.h" #include "util/mach/exception_types.h" diff --git a/test/BUILD.gn b/test/BUILD.gn index 32dc298f..047c786c 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -57,14 +57,19 @@ static_library("test") { } } + if (crashpad_is_mac || crashpad_is_ios) { + sources += [ + "mac/mach_errors.cc", + "mac/mach_errors.h", + ] + } + if (crashpad_is_mac) { sources += [ "mac/dyld.cc", "mac/dyld.h", "mac/exception_swallower.cc", "mac/exception_swallower.h", - "mac/mach_errors.cc", - "mac/mach_errors.h", "mac/mach_multiprocess.cc", "mac/mach_multiprocess.h", ] diff --git a/test/mac/exception_swallower.cc b/test/mac/exception_swallower.cc index 18c5cf71..946938fb 100644 --- a/test/mac/exception_swallower.cc +++ b/test/mac/exception_swallower.cc @@ -24,6 +24,7 @@ #include "base/mac/scoped_mach_port.h" #include "base/strings/stringprintf.h" #include "handler/mac/exception_handler_server.h" +#include "util/mach/bootstrap.h" #include "util/mach/exc_server_variants.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" diff --git a/test/mac/mach_errors.cc b/test/mac/mach_errors.cc index b68448f1..db8ed666 100644 --- a/test/mac/mach_errors.cc +++ b/test/mac/mach_errors.cc @@ -14,8 +14,6 @@ #include "test/mac/mach_errors.h" -#include <servers/bootstrap.h> - #include "base/strings/stringprintf.h" namespace { @@ -50,28 +48,5 @@ std::string MachErrorMessage(mach_error_t mach_err, const std::string& base) { FormatMachErrorNumber(mach_err).c_str()); } -std::string BootstrapErrorMessage(kern_return_t bootstrap_err, - const std::string& base) { - switch (bootstrap_err) { - case BOOTSTRAP_SUCCESS: - case BOOTSTRAP_NOT_PRIVILEGED: - case BOOTSTRAP_NAME_IN_USE: - case BOOTSTRAP_UNKNOWN_SERVICE: - case BOOTSTRAP_SERVICE_ACTIVE: - case BOOTSTRAP_BAD_COUNT: - case BOOTSTRAP_NO_MEMORY: - case BOOTSTRAP_NO_CHILDREN: - // Show known bootstrap errors in decimal because that's how they're - // defined in <servers/bootstrap.h>. - return base::StringPrintf("%s%s (%d)", - FormatBase(base).c_str(), - bootstrap_strerror(bootstrap_err), - bootstrap_err); - - default: - return MachErrorMessage(bootstrap_err, base); - } -} - } // namespace test } // namespace crashpad diff --git a/test/mac/mach_errors.h b/test/mac/mach_errors.h index 9e43ef22..0afcdadb 100644 --- a/test/mac/mach_errors.h +++ b/test/mac/mach_errors.h @@ -22,9 +22,9 @@ namespace crashpad { namespace test { -// These functions format messages in a similar way to the logging macros in -// base/mac/mach_logging.h. They exist to interoperate with gtest assertions, -// which don’t interoperate with logging but can be streamed to. +// This function formats messages in a similar way to the Mach error logging +// macros in base/mac/mach_logging.h. It exists to interoperate with gtest +// assertions, which don’t interoperate with logging but can be streamed to. // // Where non-test code could do: // MACH_CHECK(kr == KERN_SUCCESS, kr) << "vm_deallocate"; @@ -47,23 +47,6 @@ namespace test { std::string MachErrorMessage(mach_error_t mach_err, const std::string& base = std::string()); -//! \brief Formats a bootstrap error message. -//! -//! The returned string will combine the \a base string, if supplied, with a -//! textual and numeric description of the error. -//! -//! \param[in] bootstrap_err The bootstrap error code. -//! \param[in] base A string to prepend to the error description. -//! -//! \return A string of the format `"Permission denied (1100)"` if \a -//! bootstrap_err has the value `BOOTSTRAP_NOT_PRIVILEGED` on a system where -//! this is defined to be 1100. If \a base is not empty, it will be -//! prepended to this string, separated by a colon. If \a bootstrap_err is -//! not a valid bootstrap error code, it will be interpreted as a Mach error -//! code in the manner of MachErrorMessage(). -std::string BootstrapErrorMessage(kern_return_t bootstrap_err, - const std::string& base = std::string()); - } // namespace test } // namespace crashpad diff --git a/test/mac/mach_multiprocess.cc b/test/mac/mach_multiprocess.cc index f29a8b0c..59aa653e 100644 --- a/test/mac/mach_multiprocess.cc +++ b/test/mac/mach_multiprocess.cc @@ -27,6 +27,7 @@ #include "test/errors.h" #include "test/mac/mach_errors.h" #include "util/file/file_io.h" +#include "util/mach/bootstrap.h" #include "util/mach/mach_extensions.h" #include "util/mach/mach_message.h" #include "util/misc/implicit_cast.h" diff --git a/tools/mac/catch_exception_tool.cc b/tools/mac/catch_exception_tool.cc index d4dc3c12..4f40372c 100644 --- a/tools/mac/catch_exception_tool.cc +++ b/tools/mac/catch_exception_tool.cc @@ -28,6 +28,7 @@ #include "base/logging.h" #include "base/mac/mach_logging.h" #include "tools/tool_support.h" +#include "util/mach/bootstrap.h" #include "util/mach/exc_server_variants.h" #include "util/mach/exception_behaviors.h" #include "util/mach/exception_types.h" diff --git a/tools/mac/exception_port_tool.cc b/tools/mac/exception_port_tool.cc index a047e964..b9d3fdd6 100644 --- a/tools/mac/exception_port_tool.cc +++ b/tools/mac/exception_port_tool.cc @@ -30,6 +30,7 @@ #include "base/macros.h" #include "base/strings/stringprintf.h" #include "tools/tool_support.h" +#include "util/mach/bootstrap.h" #include "util/mach/exception_ports.h" #include "util/mach/mach_extensions.h" #include "util/mach/symbolic_constants_mach.h" diff --git a/util/BUILD.gn b/util/BUILD.gn index 7fe02f2b..fdd2fe14 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -248,6 +248,8 @@ static_library("util") { sources += [ "mac/xattr.cc", "mac/xattr.h", + "mach/mach_extensions.cc", + "mach/mach_extensions.h", "misc/clock_mac.cc", "misc/paths_mac.cc", "synchronization/semaphore_mac.cc", @@ -263,6 +265,8 @@ static_library("util") { "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", @@ -280,8 +284,6 @@ static_library("util") { "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", @@ -659,7 +661,10 @@ source_set("util_test") { } if (crashpad_is_mac || crashpad_is_ios) { - sources += [ "mac/xattr_test.cc" ] + sources += [ + "mac/xattr_test.cc", + "mach/mach_extensions_test.cc", + ] } if (crashpad_is_mac) { @@ -667,6 +672,7 @@ source_set("util_test") { "mac/launchd_test.mm", "mac/mac_util_test.mm", "mac/service_management_test.mm", + "mach/bootstrap_test.cc", "mach/child_port_handshake_test.cc", "mach/child_port_server_test.cc", "mach/composite_mach_message_server_test.cc", @@ -675,7 +681,6 @@ source_set("util_test") { "mach/exception_behaviors_test.cc", "mach/exception_ports_test.cc", "mach/exception_types_test.cc", - "mach/mach_extensions_test.cc", "mach/mach_message_server_test.cc", "mach/mach_message_test.cc", "mach/notify_server_test.cc", diff --git a/util/mach/bootstrap.cc b/util/mach/bootstrap.cc new file mode 100644 index 00000000..f5534372 --- /dev/null +++ b/util/mach/bootstrap.cc @@ -0,0 +1,109 @@ +// 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 "util/mach/bootstrap.h" + +#include <mach/mach.h> +#include <servers/bootstrap.h> + +#include "base/mac/mach_logging.h" + +namespace { + +// This forms the internal implementation for BootstrapCheckIn() and +// BootstrapLookUp(), which follow the same logic aside from the routine called +// and the right type returned. + +struct BootstrapCheckInTraits { + using Type = base::mac::ScopedMachReceiveRight; + static kern_return_t Call(mach_port_t bootstrap_port, + const char* service_name, + mach_port_t* service_port) { + return bootstrap_check_in(bootstrap_port, service_name, service_port); + } + static constexpr char kName[] = "bootstrap_check_in"; +}; +constexpr char BootstrapCheckInTraits::kName[]; + +struct BootstrapLookUpTraits { + using Type = base::mac::ScopedMachSendRight; + static kern_return_t Call(mach_port_t bootstrap_port, + const char* service_name, + mach_port_t* service_port) { + return bootstrap_look_up(bootstrap_port, service_name, service_port); + } + static constexpr char kName[] = "bootstrap_look_up"; +}; +constexpr char BootstrapLookUpTraits::kName[]; + +template <typename Traits> +typename Traits::Type BootstrapCheckInOrLookUp( + const std::string& service_name) { + // bootstrap_check_in() and bootstrap_look_up() silently truncate service + // names longer than BOOTSTRAP_MAX_NAME_LEN. This check ensures that the name + // will not be truncated. + if (service_name.size() >= BOOTSTRAP_MAX_NAME_LEN) { + LOG(ERROR) << Traits::kName << " " << service_name << ": name too long"; + return typename Traits::Type(MACH_PORT_NULL); + } + + mach_port_t service_port; + kern_return_t kr = + Traits::Call(bootstrap_port, service_name.c_str(), &service_port); + if (kr != BOOTSTRAP_SUCCESS) { + BOOTSTRAP_LOG(ERROR, kr) << Traits::kName << " " << service_name; + service_port = MACH_PORT_NULL; + } + + return typename Traits::Type(service_port); +} + +} // namespace + +namespace crashpad { + +base::mac::ScopedMachReceiveRight BootstrapCheckIn( + const std::string& service_name) { + return BootstrapCheckInOrLookUp<BootstrapCheckInTraits>(service_name); +} + +base::mac::ScopedMachSendRight BootstrapLookUp( + const std::string& service_name) { + base::mac::ScopedMachSendRight send( + BootstrapCheckInOrLookUp<BootstrapLookUpTraits>(service_name)); + + // It’s possible to race the bootstrap server when the receive right + // corresponding to the looked-up send right is destroyed immediately before + // the bootstrap_look_up() call. If the bootstrap server believes that + // |service_name| is still registered before processing the port-destroyed + // notification sent to it by the kernel, it will respond to a + // bootstrap_look_up() request with a send right that has become a dead name, + // which will be returned to the bootstrap_look_up() caller, translated into + // the caller’s IPC port name space, as the special MACH_PORT_DEAD port name. + // Check for that and return MACH_PORT_NULL in its place, as though the + // bootstrap server had fully processed the port-destroyed notification before + // responding to bootstrap_look_up(). + if (send.get() == MACH_PORT_DEAD) { + LOG(ERROR) << "bootstrap_look_up " << service_name << ": service is dead"; + send.reset(); + } + + return send; +} + +base::mac::ScopedMachSendRight SystemCrashReporterHandler() { + return BootstrapLookUp("com.apple.ReportCrash"); +} + +} // namespace crashpad diff --git a/util/mach/bootstrap.h b/util/mach/bootstrap.h new file mode 100644 index 00000000..680f5b91 --- /dev/null +++ b/util/mach/bootstrap.h @@ -0,0 +1,63 @@ +// 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_UTIL_MACH_BOOTSTRAP_H_ +#define CRASHPAD_UTIL_MACH_BOOTSTRAP_H_ + +#include <string> + +#include "base/mac/scoped_mach_port.h" + +namespace crashpad { + +//! \brief Makes a `boostrap_check_in()` call to the process’ bootstrap server. +//! +//! This function is provided to make it easier to call `bootstrap_check_in()` +//! while avoiding accidental leaks of the returned receive right. +//! +//! \param[in] service_name The service name to check in. +//! +//! \return On success, a receive right to the service port. On failure, +//! `MACH_PORT_NULL` with a message logged. +base::mac::ScopedMachReceiveRight BootstrapCheckIn( + const std::string& service_name); + +//! \brief Makes a `boostrap_look_up()` call to the process’ bootstrap server. +//! +//! This function is provided to make it easier to call `bootstrap_look_up()` +//! while avoiding accidental leaks of the returned send right. +//! +//! \param[in] service_name The service name to look up. +//! +//! \return On success, a send right to the service port. On failure, +//! `MACH_PORT_NULL` with a message logged. +base::mac::ScopedMachSendRight BootstrapLookUp(const std::string& service_name); + +//! \brief Obtains the system’s default Mach exception handler for crash-type +//! exceptions. +//! +//! This is obtained by looking up `"com.apple.ReportCrash"` with the bootstrap +//! server. The service name comes from the first launch agent loaded by +//! `launchd` with a `MachServices` entry having `ExceptionServer` set. This +//! launch agent is normally loaded from +//! `/System/Library/LaunchAgents/com.apple.ReportCrash.plist`. +//! +//! \return On success, a send right to an `exception_handler_t` corresponding +//! to the system’s default crash reporter. On failure, `MACH_PORT_NULL`, +//! with a message logged. +base::mac::ScopedMachSendRight SystemCrashReporterHandler(); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_MACH_BOOTSTRAP_H_ diff --git a/util/mach/bootstrap_test.cc b/util/mach/bootstrap_test.cc new file mode 100644 index 00000000..44587d08 --- /dev/null +++ b/util/mach/bootstrap_test.cc @@ -0,0 +1,70 @@ +// 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 "util/mach/bootstrap.h" + +#include "base/mac/scoped_mach_port.h" +#include "gtest/gtest.h" +#include "util/mach/mach_extensions.h" +#include "util/misc/random_string.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(Bootstrap, BootstrapCheckInAndLookUp) { + // This should always exist. + base::mac::ScopedMachSendRight report_crash( + BootstrapLookUp("com.apple.ReportCrash")); + EXPECT_NE(report_crash, kMachPortNull); + + std::string service_name = "org.chromium.crashpad.test.bootstrap_check_in."; + service_name.append(RandomString()); + + { + // The new service hasn’t checked in yet, so this should fail. + base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name)); + EXPECT_EQ(send, kMachPortNull); + + // Check it in. + base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name)); + EXPECT_NE(receive, kMachPortNull); + + // Now it should be possible to look up the new service. + send = BootstrapLookUp(service_name); + EXPECT_NE(send, kMachPortNull); + + // It shouldn’t be possible to check the service in while it’s active. + base::mac::ScopedMachReceiveRight receive_2(BootstrapCheckIn(service_name)); + EXPECT_EQ(receive_2, kMachPortNull); + } + + // The new service should be gone now. + base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name)); + EXPECT_EQ(send, kMachPortNull); + + // It should be possible to check it in again. + base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name)); + EXPECT_NE(receive, kMachPortNull); +} + +TEST(Bootstrap, SystemCrashReporterHandler) { + base::mac::ScopedMachSendRight system_crash_reporter_handler( + SystemCrashReporterHandler()); + EXPECT_TRUE(system_crash_reporter_handler.is_valid()); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/util/mach/child_port_handshake.cc b/util/mach/child_port_handshake.cc index 1891f91d..3ff9828b 100644 --- a/util/mach/child_port_handshake.cc +++ b/util/mach/child_port_handshake.cc @@ -34,6 +34,7 @@ #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "util/file/file_io.h" +#include "util/mach/bootstrap.h" #include "util/mach/child_port.h" #include "util/mach/child_port_server.h" #include "util/mach/mach_extensions.h" diff --git a/util/mach/mach_extensions.cc b/util/mach/mach_extensions.cc index 5450ab28..9e310120 100644 --- a/util/mach/mach_extensions.cc +++ b/util/mach/mach_extensions.cc @@ -14,66 +14,14 @@ #include "util/mach/mach_extensions.h" +#include <Availability.h> #include <AvailabilityMacros.h> #include <pthread.h> -#include <servers/bootstrap.h> #include "base/mac/mach_logging.h" +#include "build/build_config.h" #include "util/mac/mac_util.h" -namespace { - -// This forms the internal implementation for BootstrapCheckIn() and -// BootstrapLookUp(), which follow the same logic aside from the routine called -// and the right type returned. - -struct BootstrapCheckInTraits { - using Type = base::mac::ScopedMachReceiveRight; - static kern_return_t Call(mach_port_t bootstrap_port, - const char* service_name, - mach_port_t* service_port) { - return bootstrap_check_in(bootstrap_port, service_name, service_port); - } - static constexpr char kName[] = "bootstrap_check_in"; -}; -constexpr char BootstrapCheckInTraits::kName[]; - -struct BootstrapLookUpTraits { - using Type = base::mac::ScopedMachSendRight; - static kern_return_t Call(mach_port_t bootstrap_port, - const char* service_name, - mach_port_t* service_port) { - return bootstrap_look_up(bootstrap_port, service_name, service_port); - } - static constexpr char kName[] = "bootstrap_look_up"; -}; -constexpr char BootstrapLookUpTraits::kName[]; - -template <typename Traits> -typename Traits::Type BootstrapCheckInOrLookUp( - const std::string& service_name) { - // bootstrap_check_in() and bootstrap_look_up() silently truncate service - // names longer than BOOTSTRAP_MAX_NAME_LEN. This check ensures that the name - // will not be truncated. - if (service_name.size() >= BOOTSTRAP_MAX_NAME_LEN) { - LOG(ERROR) << Traits::kName << " " << service_name << ": name too long"; - return typename Traits::Type(MACH_PORT_NULL); - } - - mach_port_t service_port; - kern_return_t kr = Traits::Call(bootstrap_port, - service_name.c_str(), - &service_port); - if (kr != BOOTSTRAP_SUCCESS) { - BOOTSTRAP_LOG(ERROR, kr) << Traits::kName << " " << service_name; - service_port = MACH_PORT_NULL; - } - - return typename Traits::Type(service_port); -} - -} // namespace - namespace crashpad { thread_t MachThreadSelf() { @@ -97,7 +45,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 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 +#if defined(OS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 +// iOS 7 ≅ macOS 10.9. +#error This code was not ported to iOS versions older than 7 +#endif + +#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 const int mac_os_x_minor_version = MacOSXMinorVersion(); #endif @@ -114,7 +67,7 @@ exception_mask_t ExcMaskAll() { EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT | EXC_MASK_MACHINE; -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 +#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 if (mac_os_x_minor_version < 8) { return kExcMaskAll_10_6; } @@ -124,7 +77,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 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 +#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 if (mac_os_x_minor_version < 9) { return kExcMaskAll_10_8; } @@ -139,7 +92,12 @@ exception_mask_t ExcMaskAll() { exception_mask_t ExcMaskValid() { const exception_mask_t kExcMaskValid_10_6 = ExcMaskAll() | EXC_MASK_CRASH; -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11 +#if defined(OS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0 +// iOS 9 ≅ macOS 10.11. +#error This code was not ported to iOS versions older than 9 +#endif + +#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11 if (MacOSXMinorVersion() < 11) { return kExcMaskValid_10_6; } @@ -151,37 +109,4 @@ exception_mask_t ExcMaskValid() { return kExcMaskValid_10_11; } -base::mac::ScopedMachReceiveRight BootstrapCheckIn( - const std::string& service_name) { - return BootstrapCheckInOrLookUp<BootstrapCheckInTraits>(service_name); -} - -base::mac::ScopedMachSendRight BootstrapLookUp( - const std::string& service_name) { - base::mac::ScopedMachSendRight send( - BootstrapCheckInOrLookUp<BootstrapLookUpTraits>(service_name)); - - // It’s possible to race the bootstrap server when the receive right - // corresponding to the looked-up send right is destroyed immediately before - // the bootstrap_look_up() call. If the bootstrap server believes that - // |service_name| is still registered before processing the port-destroyed - // notification sent to it by the kernel, it will respond to a - // bootstrap_look_up() request with a send right that has become a dead name, - // which will be returned to the bootstrap_look_up() caller, translated into - // the caller’s IPC port name space, as the special MACH_PORT_DEAD port name. - // Check for that and return MACH_PORT_NULL in its place, as though the - // bootstrap server had fully processed the port-destroyed notification before - // responding to bootstrap_look_up(). - if (send.get() == MACH_PORT_DEAD) { - LOG(ERROR) << "bootstrap_look_up " << service_name << ": service is dead"; - send.reset(); - } - - return send; -} - -base::mac::ScopedMachSendRight SystemCrashReporterHandler() { - return BootstrapLookUp("com.apple.ReportCrash"); -} - } // namespace crashpad diff --git a/util/mach/mach_extensions.h b/util/mach/mach_extensions.h index 25e401c2..9247ce94 100644 --- a/util/mach/mach_extensions.h +++ b/util/mach/mach_extensions.h @@ -17,10 +17,6 @@ #include <mach/mach.h> -#include <string> - -#include "base/mac/scoped_mach_port.h" - namespace crashpad { //! \brief `MACH_PORT_NULL` with the correct type for a Mach port, @@ -119,43 +115,6 @@ exception_mask_t ExcMaskAll(); //! support is present. exception_mask_t ExcMaskValid(); -//! \brief Makes a `boostrap_check_in()` call to the process’ bootstrap server. -//! -//! This function is provided to make it easier to call `bootstrap_check_in()` -//! while avoiding accidental leaks of the returned receive right. -//! -//! \param[in] service_name The service name to check in. -//! -//! \return On success, a receive right to the service port. On failure, -//! `MACH_PORT_NULL` with a message logged. -base::mac::ScopedMachReceiveRight BootstrapCheckIn( - const std::string& service_name); - -//! \brief Makes a `boostrap_look_up()` call to the process’ bootstrap server. -//! -//! This function is provided to make it easier to call `bootstrap_look_up()` -//! while avoiding accidental leaks of the returned send right. -//! -//! \param[in] service_name The service name to look up. -//! -//! \return On success, a send right to the service port. On failure, -//! `MACH_PORT_NULL` with a message logged. -base::mac::ScopedMachSendRight BootstrapLookUp(const std::string& service_name); - -//! \brief Obtains the system’s default Mach exception handler for crash-type -//! exceptions. -//! -//! This is obtained by looking up `"com.apple.ReportCrash"` with the bootstrap -//! server. The service name comes from the first launch agent loaded by -//! `launchd` with a `MachServices` entry having `ExceptionServer` set. This -//! launch agent is normally loaded from -//! `/System/Library/LaunchAgents/com.apple.ReportCrash.plist`. -//! -//! \return On success, a send right to an `exception_handler_t` corresponding -//! to the system’s default crash reporter. On failure, `MACH_PORT_NULL`, -//! with a message logged. -base::mac::ScopedMachSendRight SystemCrashReporterHandler(); - } // namespace crashpad #endif // CRASHPAD_UTIL_MACH_MACH_EXTENSIONS_H_ diff --git a/util/mach/mach_extensions_test.cc b/util/mach/mach_extensions_test.cc index 1c5b368c..748e0aa5 100644 --- a/util/mach/mach_extensions_test.cc +++ b/util/mach/mach_extensions_test.cc @@ -15,10 +15,10 @@ #include "util/mach/mach_extensions.h" #include "base/mac/scoped_mach_port.h" +#include "build/build_config.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" #include "util/mac/mac_util.h" -#include "util/misc/random_string.h" namespace crashpad { namespace test { @@ -80,6 +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) + // Assume at least iOS 7 (≅ macOS 10.9). + EXPECT_TRUE(exc_mask_all & EXC_MASK_RESOURCE); + EXPECT_TRUE(exc_mask_all & EXC_MASK_GUARD); +#else // OS_IOS const int mac_os_x_minor_version = MacOSXMinorVersion(); if (mac_os_x_minor_version >= 8) { EXPECT_TRUE(exc_mask_all & EXC_MASK_RESOURCE); @@ -92,6 +97,7 @@ TEST(MachExtensions, ExcMaskAll) { } else { EXPECT_FALSE(exc_mask_all & EXC_MASK_GUARD); } +#endif // OS_IOS // Bit 0 should not be set. EXPECT_FALSE(ExcMaskAll() & 1); @@ -106,6 +112,12 @@ TEST(MachExtensions, ExcMaskValid) { EXPECT_TRUE(exc_mask_valid & EXC_MASK_CRASH); +#if defined(OS_IOS) + // Assume at least iOS 9 (≅ macOS 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 const int mac_os_x_minor_version = MacOSXMinorVersion(); if (mac_os_x_minor_version >= 8) { EXPECT_TRUE(exc_mask_valid & EXC_MASK_RESOURCE); @@ -124,6 +136,7 @@ TEST(MachExtensions, ExcMaskValid) { } else { EXPECT_FALSE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY); } +#endif // OS_IOS // Bit 0 should not be set. EXPECT_FALSE(ExcMaskValid() & 1); @@ -132,48 +145,6 @@ TEST(MachExtensions, ExcMaskValid) { EXPECT_TRUE(ExcMaskValid() & ~ExcMaskAll()); } -TEST(MachExtensions, BootstrapCheckInAndLookUp) { - // This should always exist. - base::mac::ScopedMachSendRight - report_crash(BootstrapLookUp("com.apple.ReportCrash")); - EXPECT_NE(report_crash, kMachPortNull); - - std::string service_name = "org.chromium.crashpad.test.bootstrap_check_in."; - service_name.append(RandomString()); - - { - // The new service hasn’t checked in yet, so this should fail. - base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name)); - EXPECT_EQ(send, kMachPortNull); - - // Check it in. - base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name)); - EXPECT_NE(receive, kMachPortNull); - - // Now it should be possible to look up the new service. - send = BootstrapLookUp(service_name); - EXPECT_NE(send, kMachPortNull); - - // It shouldn’t be possible to check the service in while it’s active. - base::mac::ScopedMachReceiveRight receive_2(BootstrapCheckIn(service_name)); - EXPECT_EQ(receive_2, kMachPortNull); - } - - // The new service should be gone now. - base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name)); - EXPECT_EQ(send, kMachPortNull); - - // It should be possible to check it in again. - base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name)); - EXPECT_NE(receive, kMachPortNull); -} - -TEST(MachExtensions, SystemCrashReporterHandler) { - base::mac::ScopedMachSendRight - system_crash_reporter_handler(SystemCrashReporterHandler()); - EXPECT_TRUE(system_crash_reporter_handler.is_valid()); -} - } // namespace } // namespace test } // namespace crashpad From 8dbbaff2e1a5b90ba2d967a90c0cfc66a15f1f00 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 17 Apr 2020 16:43:39 -0400 Subject: [PATCH 384/401] ios: Provide a copy of exc.defs and run mig on it to generate exc stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The iOS SDK doesn’t include a copy of <mach/exc.defs>. It only provides <mach/exc.h>, which is just the user-side header. To obtain declarations and implementations of the server-side stubs, a current copy of <mach/exc.defs> is added to third_party, and the mig action in util is updated to use it on iOS. The three other mig subsystems that Crashpad uses are not brought to iOS: - mach_exc is identical to exc except it always uses 64-bit quantities for addresses in place of exc’s use of quantiies sized for native pointers. Because all iOS work is limited to a single process, there is no need to consider cross-process operation with variable bitness, so mach_exc is unnecessary. We’re also only targeting 64-bit for iOS, so exc will always suffice. This follows the spirit of other mach_-prefixed routines on iOS, where Apple forbids mach_vm_read to user applications but permits vm_read. - notify is primarily used on macOS in the Crashpad handler process to receive a no-senders notification, which is used to trigger handler shutdown when it has no more clients. This is not believed to be useful to Crashpad on iOS, which is restricted to single-process operation. - child_port is a Crashpad-specific subsystem used to pass Mach rights between processes, but is similarly useless when restricted to single-process operation as on iOS. Bug: crashpad:31 Change-Id: Id4cb3cdd529814438d378c20702c82c1e89dd2be Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2154530 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Justin Cohen <justincohen@chromium.org> --- .../xnu/EXTERNAL_HEADERS/mach-o/loader.h | 57 +++++++- third_party/xnu/README.crashpad | 9 +- third_party/xnu/osfmk/mach/exc.defs | 133 ++++++++++++++++++ util/BUILD.gn | 39 +++-- 4 files changed, 214 insertions(+), 24 deletions(-) create mode 100644 third_party/xnu/osfmk/mach/exc.defs diff --git a/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h b/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h index 3b7f0ee3..72e8c39b 100644 --- a/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h +++ b/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h @@ -40,6 +40,13 @@ */ #include <mach/vm_prot.h> +/* + * <machine/thread_status.h> is expected to define the flavors of the thread + * states and the structures of those flavors for each machine. +#include <mach/machine/thread_status.h> +#include <architecture/byte_order.h> + */ + /* * The 32-bit mach header appears at the very beginning of the object file for * 32-bit architectures. @@ -203,6 +210,22 @@ struct mach_header_64 { #define MH_APP_EXTENSION_SAFE 0x02000000 /* The code was linked for use in an application extension. */ +#define MH_NLIST_OUTOFSYNC_WITH_DYLDINFO 0x04000000 /* The external symbols + listed in the nlist symbol table do + not include all the symbols listed in + the dyld info. */ + +#define MH_SIM_SUPPORT 0x08000000 /* Allow LC_MIN_VERSION_MACOS and + LC_BUILD_VERSION load commands with + the platforms macOS, iOSMac, + iOSSimulator, tvOSSimulator and + watchOSSimulator. */ + +#define MH_DYLIB_IN_CACHE 0x80000000 /* Only for use on dylibs. When this bit + is set, the dylib is part of the dyld + shared cache, rather than loose in + the filesystem. */ + /* * The load commands directly follow the mach_header. The total size of all * of the commands is given by the sizeofcmds field in the mach_header. All @@ -297,6 +320,8 @@ struct load_command { #define LC_VERSION_MIN_WATCHOS 0x30 /* build for Watch min OS version */ #define LC_NOTE 0x31 /* arbitrary data included within a Mach-O file */ #define LC_BUILD_VERSION 0x32 /* build for platform min OS version */ +#define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD) /* used with linkedit_data_command, payload is trie */ +#define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD) /* used with linkedit_data_command */ /* * A variable length string in a load command is represented by an lc_str @@ -374,6 +399,9 @@ struct segment_command_64 { /* for 64-bit architectures */ first page of the segment is not protected. All other pages of the segment are protected. */ +#define SG_READ_ONLY 0x10 /* This segment is made read-only after fixups */ + + /* * A segment is made up of zero or more sections. Non-MH_OBJECT files have @@ -499,6 +527,8 @@ struct section_64 { /* for 64-bit architectures */ #define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15 /* functions to call to initialize TLV values */ +#define S_INIT_FUNC_OFFSETS 0x16 /* 32-bit offsets to + initializers */ /* * Constants for the section attributes part of the flags field of a section @@ -760,14 +790,14 @@ struct dylinker_command { * Thread commands contain machine-specific data structures suitable for * use in the thread state primitives. The machine specific data structures * follow the struct thread_command as follows. - * Each flavor of machine specific data structure is preceded by an unsigned - * long constant for the flavor of that data structure, an uint32_t - * that is the count of longs of the size of the state data structure and then + * Each flavor of machine specific data structure is preceded by an uint32_t + * constant for the flavor of that data structure, an uint32_t that is the + * count of uint32_t's of the size of the state data structure and then * the state data structure follows. This triple may be repeated for many * flavors. The constants for the flavors, counts and state data structure * definitions are expected to be in the header file <machine/thread_status.h>. * These machine specific data structures sizes must be multiples of - * 4 bytes The cmdsize reflects the total size of the thread_command + * 4 bytes. The cmdsize reflects the total size of the thread_command * and all of the sizes of the constants for the flavors, counts and state * data structures. * @@ -781,7 +811,7 @@ struct thread_command { uint32_t cmd; /* LC_THREAD or LC_UNIXTHREAD */ uint32_t cmdsize; /* total size of this command */ /* uint32_t flavor flavor of thread state */ - /* uint32_t count count of longs in thread state */ + /* uint32_t count count of uint32_t's in thread state */ /* struct XXX_thread_state state thread state for this flavor */ /* ... */ }; @@ -1157,8 +1187,10 @@ struct rpath_command { struct linkedit_data_command { uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, - LC_DYLIB_CODE_SIGN_DRS or - LC_LINKER_OPTIMIZATION_HINT. */ + LC_DYLIB_CODE_SIGN_DRS, + LC_LINKER_OPTIMIZATION_HINT, + LC_DYLD_EXPORTS_TRIE, or + LC_DYLD_CHAINED_FIXUPS. */ uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */ uint32_t dataoff; /* file offset of data in __LINKEDIT segment */ uint32_t datasize; /* file size of data in __LINKEDIT segment */ @@ -1231,6 +1263,12 @@ struct build_tool_version { #define PLATFORM_IOS 2 #define PLATFORM_TVOS 3 #define PLATFORM_WATCHOS 4 +#define PLATFORM_BRIDGEOS 5 +#define PLATFORM_IOSMAC 6 +#define PLATFORM_IOSSIMULATOR 7 +#define PLATFORM_TVOSSIMULATOR 8 +#define PLATFORM_WATCHOSSIMULATOR 9 +#define PLATFORM_DRIVERKIT 10 /* Known values for the tool field above. */ #define TOOL_CLANG 1 @@ -1378,6 +1416,7 @@ struct dyld_info_command { #define BIND_SPECIAL_DYLIB_SELF 0 #define BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE -1 #define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2 +#define BIND_SPECIAL_DYLIB_WEAK_LOOKUP -3 #define BIND_SYMBOL_FLAGS_WEAK_IMPORT 0x1 #define BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION 0x8 @@ -1397,6 +1436,9 @@ struct dyld_info_command { #define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xA0 #define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xB0 #define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xC0 +#define BIND_OPCODE_THREADED 0xD0 +#define BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB 0x00 +#define BIND_SUBOPCODE_THREADED_APPLY 0x01 /* @@ -1406,6 +1448,7 @@ struct dyld_info_command { #define EXPORT_SYMBOL_FLAGS_KIND_MASK 0x03 #define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00 #define EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL 0x01 +#define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02 #define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04 #define EXPORT_SYMBOL_FLAGS_REEXPORT 0x08 #define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 0x10 diff --git a/third_party/xnu/README.crashpad b/third_party/xnu/README.crashpad index 274faf16..55a67d5a 100644 --- a/third_party/xnu/README.crashpad +++ b/third_party/xnu/README.crashpad @@ -2,7 +2,7 @@ Name: XNU Short Name: xnu URL: https://opensource.apple.com/source/xnu/ URL: https://opensource.apple.com/tarballs/xnu/ -Version: 4903.221.2 (from macOS 10.14.1) +Version: 6153.11.26 (from macOS 10.15.0) License: APSL 2.0 License File: APPLE_LICENSE Security Critical: no @@ -11,9 +11,12 @@ Description: XNU is the operating system kernel used on macOS and other Apple systems. Local Modifications: - - Only EXTERNAL_HEADERS/mach-o/loader.h is included. Its #includes of + - EXTERNAL_HEADERS/mach-o/loader.h is present. Its #includes of <mach/machine/thread_status.h> and <architecture/byte_order.h> have been - removed as unnecessary. Note that its #includes of <mach/machine.h> and + commented out as unnecessary. Note that its #includes of <mach/machine.h> and <mach/vm_prot.h> have been retained but these headers have not been provided. External headers must be made available to provide the cpu_type_t, cpu_subtype_t, and vm_prot_t types. + - osfmk/mach/exc.defs is present, to fill in for <mach/exc.defs> on iOS, where + it is missing. + - Anything not listed above is omitted. diff --git a/third_party/xnu/osfmk/mach/exc.defs b/third_party/xnu/osfmk/mach/exc.defs new file mode 100644 index 00000000..734e7408 --- /dev/null +++ b/third_party/xnu/osfmk/mach/exc.defs @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ +/* + * Abstract: + * MiG definitions file for Mach exception interface. + */ + +subsystem +#if KERNEL_SERVER + KernelServer +#endif /* KERNEL_SERVER */ + +#if KERNEL_USER + KernelUser +#endif + exc 2401; + +#include <mach/std_types.defs> +#include <mach/mach_types.defs> + +ServerPrefix catch_; + +type exception_data_t = array[*:2] of integer_t; +type exception_type_t = int; + +routine exception_raise( + exception_port : mach_port_t; + thread : mach_port_t; + task : mach_port_t; + exception : exception_type_t; + code : exception_data_t +#if EXC_SERVER_SECTOKEN + ; + ServerSecToken stoken : security_token_t +#endif +#if EXC_SERVER_AUDITTOKEN + ; + ServerAuditToken atoken: audit_token_t +#endif + ); + +routine exception_raise_state( + exception_port : mach_port_t; + exception : exception_type_t; + code : exception_data_t, const; + inout flavor : int; + old_state : thread_state_t, const; + out new_state : thread_state_t +#if EXC_SERVER_SECTOKEN + ; + ServerSecToken stoken : security_token_t +#endif +#if EXC_SERVER_AUDITTOKEN + ; + ServerAuditToken atoken: audit_token_t +#endif + ); + +routine exception_raise_state_identity( + exception_port : mach_port_t; + thread : mach_port_t; + task : mach_port_t; + exception : exception_type_t; + code : exception_data_t; + inout flavor : int; + old_state : thread_state_t; + out new_state : thread_state_t +#if EXC_SERVER_SECTOKEN + ; + ServerSecToken stoken : security_token_t +#endif +#if EXC_SERVER_AUDITTOKEN + ; + ServerAuditToken atoken: audit_token_t +#endif + ); + +/* vim: set ft=c : */ diff --git a/util/BUILD.gn b/util/BUILD.gn index fdd2fe14..56346c11 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -22,22 +22,28 @@ if (crashpad_is_in_chromium) { set_sources_assignment_filter([]) } -if (crashpad_is_mac) { - if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { - import("//build/config/sysroot.gni") - } else { - import("//third_party/mini_chromium/mini_chromium/build/sysroot.gni") +if (crashpad_is_mac || crashpad_is_ios) { + if (crashpad_is_mac) { + if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { + import("//build/config/sysroot.gni") + } else { + import("//third_party/mini_chromium/mini_chromium/build/sysroot.gni") + } } action_foreach("mig") { script = "mach/mig.py" - sources = [ - "$sysroot/usr/include/mach/exc.defs", - "$sysroot/usr/include/mach/mach_exc.defs", - "$sysroot/usr/include/mach/notify.defs", - "mach/child_port.defs", - ] + if (crashpad_is_mac) { + sources = [ + "$sysroot/usr/include/mach/exc.defs", + "$sysroot/usr/include/mach/mach_exc.defs", + "$sysroot/usr/include/mach/notify.defs", + "mach/child_port.defs", + ] + } else if (crashpad_is_ios) { + sources = [ "../third_party/xnu/osfmk/mach/exc.defs" ] + } outputs = [ "$target_gen_dir/mach/{{source_name_part}}User.c", @@ -67,7 +73,7 @@ if (crashpad_is_mac) { ] } } - if (sysroot != "") { + if (!crashpad_is_ios && sysroot != "") { args += [ "--sdk", sysroot, @@ -510,6 +516,13 @@ static_library("util") { deps += [ "../third_party/mini_chromium:base" ] + if (crashpad_is_mac || crashpad_is_ios) { + include_dirs += [ "$root_build_dir/gen" ] + deps += [ + ":mig_output", + ] + } + if (crashpad_is_mac) { libs = [ "bsm", @@ -518,10 +531,8 @@ static_library("util") { "IOKit.framework", ] deps += [ - ":mig_output", "../third_party/apple_cf:apple_cf", ] - include_dirs += [ "$root_build_dir/gen" ] } if (crashpad_is_win) { From 4cb79941fcd4bfe6877e8d061aea5b6ab5901271 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Fri, 17 Apr 2020 17:45:18 -0400 Subject: [PATCH 385/401] ios: Build four more Mach message and exception utilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables the following code in util/mach on iOS: - exception_behaviors.{cc,h} - exception_ports.{cc,h} - mach_message.{cc,h} - mach_message_server.{cc,h} Only the ExceptionBehaviors and MachMessage tests are built, because the other two are tested by multiprocess tests that won’t run on iOS. The AuditPIDFromMachMessageTrailer function from mach_message.h is excluded on iOS because it relies on <bsm/libbsm.h>, which is broken on iOS: it depends on <bsm/audit_record.h>, which is missing from the SDK. Additionally, the BSM function that Crashpad uses, audit_token_to_au32, is marked as unavailable on iOS. Crashpad uses it on macOS to authenticate Mach messages sent by other processes, but this is moot on iOS. Bug: crashpad:31 Change-Id: I5ebc4b80543989b9cd0b85b82eb4b3ff98c44e6c Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2155086 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/BUILD.gn | 28 +++++------- util/mach/mach_message.cc | 73 ++++++++++++++++------------- util/mach/mach_message.h | 34 ++++++++------ util/mach/mach_message_test.cc | 84 ++++++++++++++++++---------------- 4 files changed, 116 insertions(+), 103 deletions(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index 56346c11..10ca3a55 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -254,8 +254,16 @@ static_library("util") { sources += [ "mac/xattr.cc", "mac/xattr.h", + "mach/exception_behaviors.cc", + "mach/exception_behaviors.h", + "mach/exception_ports.cc", + "mach/exception_ports.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", "misc/clock_mac.cc", "misc/paths_mac.cc", "synchronization/semaphore_mac.cc", @@ -284,16 +292,8 @@ static_library("util") { "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_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", @@ -518,9 +518,7 @@ static_library("util") { if (crashpad_is_mac || crashpad_is_ios) { include_dirs += [ "$root_build_dir/gen" ] - deps += [ - ":mig_output", - ] + deps += [ ":mig_output" ] } if (crashpad_is_mac) { @@ -530,9 +528,7 @@ static_library("util") { "Foundation.framework", "IOKit.framework", ] - deps += [ - "../third_party/apple_cf:apple_cf", - ] + deps += [ "../third_party/apple_cf:apple_cf" ] } if (crashpad_is_win) { @@ -674,7 +670,9 @@ source_set("util_test") { if (crashpad_is_mac || crashpad_is_ios) { sources += [ "mac/xattr_test.cc", + "mach/exception_behaviors_test.cc", "mach/mach_extensions_test.cc", + "mach/mach_message_test.cc", ] } @@ -689,11 +687,9 @@ source_set("util_test") { "mach/composite_mach_message_server_test.cc", "mach/exc_client_variants_test.cc", "mach/exc_server_variants_test.cc", - "mach/exception_behaviors_test.cc", "mach/exception_ports_test.cc", "mach/exception_types_test.cc", "mach/mach_message_server_test.cc", - "mach/mach_message_test.cc", "mach/notify_server_test.cc", "mach/scoped_task_suspend_test.cc", "mach/symbolic_constants_mach_test.cc", diff --git a/util/mach/mach_message.cc b/util/mach/mach_message.cc index 5294c035..72d71e3e 100644 --- a/util/mach/mach_message.cc +++ b/util/mach/mach_message.cc @@ -15,7 +15,6 @@ #include "util/mach/mach_message.h" #include <AvailabilityMacros.h> -#include <bsm/libbsm.h> #include <limits> @@ -24,6 +23,10 @@ #include "util/misc/clock.h" #include "util/misc/implicit_cast.h" +#if !defined(OS_IOS) +#include <bsm/libbsm.h> +#endif // !OS_IOS + namespace crashpad { namespace { @@ -217,38 +220,6 @@ const mach_msg_trailer_t* MachMessageTrailerFromHeader( return reinterpret_cast<const mach_msg_trailer_t*>(trailer_address); } -pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer) { - if (trailer->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0) { - LOG(ERROR) << "unexpected msgh_trailer_type " << trailer->msgh_trailer_type; - return -1; - } - if (trailer->msgh_trailer_size < - REQUESTED_TRAILER_SIZE(kMachMessageReceiveAuditTrailer)) { - LOG(ERROR) << "small msgh_trailer_size " << trailer->msgh_trailer_size; - return -1; - } - - const mach_msg_audit_trailer_t* audit_trailer = - reinterpret_cast<const mach_msg_audit_trailer_t*>(trailer); - -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 - pid_t audit_pid; - audit_token_to_au32(audit_trailer->msgh_audit, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - &audit_pid, - nullptr, - nullptr); -#else - pid_t audit_pid = audit_token_to_pid(audit_trailer->msgh_audit); -#endif - - return audit_pid; -} - bool MachMessageDestroyReceivedPort(mach_port_t port, mach_msg_type_name_t port_right_type) { // This implements a subset of 10.10.5 @@ -282,4 +253,40 @@ bool MachMessageDestroyReceivedPort(mach_port_t port, } } +#if !defined(OS_IOS) + +pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer) { + if (trailer->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0) { + LOG(ERROR) << "unexpected msgh_trailer_type " << trailer->msgh_trailer_type; + return -1; + } + if (trailer->msgh_trailer_size < + REQUESTED_TRAILER_SIZE(kMachMessageReceiveAuditTrailer)) { + LOG(ERROR) << "small msgh_trailer_size " << trailer->msgh_trailer_size; + return -1; + } + + const mach_msg_audit_trailer_t* audit_trailer = + reinterpret_cast<const mach_msg_audit_trailer_t*>(trailer); + +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8 + pid_t audit_pid; + audit_token_to_au32(audit_trailer->msgh_audit, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + &audit_pid, + nullptr, + nullptr); +#else + pid_t audit_pid = audit_token_to_pid(audit_trailer->msgh_audit); +#endif + + return audit_pid; +} + +#endif // !OS_IOS + } // namespace crashpad diff --git a/util/mach/mach_message.h b/util/mach/mach_message.h index e0fc6f6f..fd8d3d58 100644 --- a/util/mach/mach_message.h +++ b/util/mach/mach_message.h @@ -19,6 +19,8 @@ #include <stdint.h> #include <sys/types.h> +#include "build/build_config.h" + namespace crashpad { //! \brief A Mach message option specifying that an audit trailer should be @@ -166,6 +168,23 @@ void SetMIGReplyError(mach_msg_header_t* out_header, kern_return_t error); const mach_msg_trailer_t* MachMessageTrailerFromHeader( const mach_msg_header_t* header); +//! \brief Destroys or deallocates a Mach port received in a Mach message. +//! +//! This function disposes of port rights received in a Mach message. Receive +//! rights will be destroyed with `mach_port_mod_refs()`. Send and send-once +//! rights will be deallocated with `mach_port_deallocate()`. +//! +//! \param[in] port The port to destroy or deallocate. +//! \param[in] port_right_type The right type held for \a port: +//! `MACH_MSG_TYPE_PORT_RECEIVE`, `MACH_MSG_TYPE_PORT_SEND`, or +//! `MACH_MSG_TYPE_PORT_SEND_ONCE`. +//! +//! \return `true` on success, or `false` on failure with a message logged. +bool MachMessageDestroyReceivedPort(mach_port_t port, + mach_msg_type_name_t port_right_type); + +#if !defined(OS_IOS) || DOXYGEN + //! \brief Returns the process ID of a Mach message’s sender from its audit //! trailer. //! @@ -182,20 +201,7 @@ const mach_msg_trailer_t* MachMessageTrailerFromHeader( //! audit information. pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer); -//! \brief Destroys or deallocates a Mach port received in a Mach message. -//! -//! This function disposes of port rights received in a Mach message. Receive -//! rights will be destroyed with `mach_port_mod_refs()`. Send and send-once -//! rights will be deallocated with `mach_port_deallocate()`. -//! -//! \param[in] port The port to destroy or deallocate. -//! \param[in] port_right_type The right type held for \a port: -//! `MACH_MSG_TYPE_PORT_RECEIVE`, `MACH_MSG_TYPE_PORT_SEND`, or -//! `MACH_MSG_TYPE_PORT_SEND_ONCE`. -//! -//! \return `true` on success, or `false` on failure with a message logged. -bool MachMessageDestroyReceivedPort(mach_port_t port, - mach_msg_type_name_t port_right_type); +#endif // !OS_IOS } // namespace crashpad diff --git a/util/mach/mach_message_test.cc b/util/mach/mach_message_test.cc index b00b187a..729e3a34 100644 --- a/util/mach/mach_message_test.cc +++ b/util/mach/mach_message_test.cc @@ -109,46 +109,6 @@ TEST(MachMessage, MachMessageTrailerFromHeader) { EXPECT_EQ(MachMessageTrailerFromHeader(&test.receive), &test.receive.trailer); } -TEST(MachMessage, AuditPIDFromMachMessageTrailer) { - base::mac::ScopedMachReceiveRight port(NewMachPort(MACH_PORT_RIGHT_RECEIVE)); - ASSERT_NE(port, kMachPortNull); - - mach_msg_empty_send_t send = {}; - send.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND_ONCE, 0); - send.header.msgh_size = sizeof(send); - send.header.msgh_remote_port = port.get(); - mach_msg_return_t mr = - MachMessageWithDeadline(&send.header, - MACH_SEND_MSG, - 0, - MACH_PORT_NULL, - kMachMessageDeadlineNonblocking, - MACH_PORT_NULL, - false); - ASSERT_EQ(mr, MACH_MSG_SUCCESS) - << MachErrorMessage(mr, "MachMessageWithDeadline send"); - - struct EmptyReceiveMessageWithAuditTrailer : public mach_msg_empty_send_t { - union { - mach_msg_trailer_t trailer; - mach_msg_audit_trailer_t audit_trailer; - }; - }; - - EmptyReceiveMessageWithAuditTrailer receive; - mr = MachMessageWithDeadline(&receive.header, - MACH_RCV_MSG | kMachMessageReceiveAuditTrailer, - sizeof(receive), - port.get(), - kMachMessageDeadlineNonblocking, - MACH_PORT_NULL, - false); - ASSERT_EQ(mr, MACH_MSG_SUCCESS) - << MachErrorMessage(mr, "MachMessageWithDeadline receive"); - - EXPECT_EQ(AuditPIDFromMachMessageTrailer(&receive.trailer), getpid()); -} - TEST(MachMessage, MachMessageDestroyReceivedPort) { mach_port_t port = NewMachPort(MACH_PORT_RIGHT_RECEIVE); ASSERT_NE(port, kMachPortNull); @@ -198,6 +158,50 @@ TEST(MachMessage, MachMessageDestroyReceivedPort) { EXPECT_TRUE(MachMessageDestroyReceivedPort(port, MACH_MSG_TYPE_PORT_SEND)); } +#if !defined(OS_IOS) + +TEST(MachMessage, AuditPIDFromMachMessageTrailer) { + base::mac::ScopedMachReceiveRight port(NewMachPort(MACH_PORT_RIGHT_RECEIVE)); + ASSERT_NE(port, kMachPortNull); + + mach_msg_empty_send_t send = {}; + send.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND_ONCE, 0); + send.header.msgh_size = sizeof(send); + send.header.msgh_remote_port = port.get(); + mach_msg_return_t mr = + MachMessageWithDeadline(&send.header, + MACH_SEND_MSG, + 0, + MACH_PORT_NULL, + kMachMessageDeadlineNonblocking, + MACH_PORT_NULL, + false); + ASSERT_EQ(mr, MACH_MSG_SUCCESS) + << MachErrorMessage(mr, "MachMessageWithDeadline send"); + + struct EmptyReceiveMessageWithAuditTrailer : public mach_msg_empty_send_t { + union { + mach_msg_trailer_t trailer; + mach_msg_audit_trailer_t audit_trailer; + }; + }; + + EmptyReceiveMessageWithAuditTrailer receive; + mr = MachMessageWithDeadline(&receive.header, + MACH_RCV_MSG | kMachMessageReceiveAuditTrailer, + sizeof(receive), + port.get(), + kMachMessageDeadlineNonblocking, + MACH_PORT_NULL, + false); + ASSERT_EQ(mr, MACH_MSG_SUCCESS) + << MachErrorMessage(mr, "MachMessageWithDeadline receive"); + + EXPECT_EQ(AuditPIDFromMachMessageTrailer(&receive.trailer), getpid()); +} + +#endif // !OS_IOS + } // namespace } // namespace test } // namespace crashpad From 64c65b575728fd6663901ca1a211ae50e438c5c1 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 20 Apr 2020 10:39:44 -0400 Subject: [PATCH 386/401] ios: Build and test the minidump library Bug: crashpad:31 Change-Id: I7c3974907114430a9674c3baae3ae359d5ed596e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2156965 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- BUILD.gn | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index 0b16a6df..381271a8 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -37,13 +37,13 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { test("crashpad_tests") { deps = [ "client:client_test", + "minidump:minidump_test", "test:gmock_main", "test:test_test", ] if (!crashpad_is_ios) { deps += [ "handler:handler_test", - "minidump:minidump_test", "snapshot:snapshot_test", ] } @@ -192,9 +192,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "minidump:minidump_test", "test:gtest_main", ] - if (crashpad_is_ios) { - deps -= [ "minidump:minidump_test" ] - } } test("crashpad_snapshot_test") { From 3e748e9c4e0deccf2f95fe3c0ca6ea58b46632b0 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 21 Apr 2020 10:56:57 -0400 Subject: [PATCH 387/401] ios: Provide a copy of mach_exc.defs and run mig on it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This updates (and corrects) 8dbbaff2e1a5, which added exc.defs, by adding mach_exc.defs too. The difference betwen the exc and mach_exc subsystems is that the |code| parameter is int[] in exc and int64_t[] in mach_exc. Many exceptions carry the exception address in code[1], and a 32-bit int results in the exception address being truncated in exc. No information is lost in mach_exc, where a 64-bit int64_t is used. In 8dbbaff2e1a5, I misremembered the type of the |code| parameter as a type derived from uintptr_t, such as vm_address_t, an integer as wide as a pointer. I was wrong, and mach_exc is necessary. I also noted that Apple normally forbids mach_-prefixed interfaces in favor of the prefix-less ones for the reasons I mentioned, and that, all else being equal, it was desirable to adhere to the spirit of that convention. Because neither exc nor mach_exc are available in the SDK, it’s moot from a technical perspective, as we need to provide our own stubs either way. Bug: crashpad:31 Change-Id: Ied1be470e653b2bead1a283cb8b9283d210c328d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2159286 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- third_party/xnu/README.crashpad | 4 +- third_party/xnu/osfmk/mach/mach_exc.defs | 133 +++++++++++++++++++++++ util/BUILD.gn | 5 +- 3 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 third_party/xnu/osfmk/mach/mach_exc.defs diff --git a/third_party/xnu/README.crashpad b/third_party/xnu/README.crashpad index 55a67d5a..813f9886 100644 --- a/third_party/xnu/README.crashpad +++ b/third_party/xnu/README.crashpad @@ -17,6 +17,6 @@ Local Modifications: <mach/vm_prot.h> have been retained but these headers have not been provided. External headers must be made available to provide the cpu_type_t, cpu_subtype_t, and vm_prot_t types. - - osfmk/mach/exc.defs is present, to fill in for <mach/exc.defs> on iOS, where - it is missing. + - osfmk/mach/exc.defs and osfmk/mach/mach_exc.defs are present, to fill in + for <mach/exc.defs> and <mach/mach_exc.defs> on iOS, where they are missing. - Anything not listed above is omitted. diff --git a/third_party/xnu/osfmk/mach/mach_exc.defs b/third_party/xnu/osfmk/mach/mach_exc.defs new file mode 100644 index 00000000..5ce6427b --- /dev/null +++ b/third_party/xnu/osfmk/mach/mach_exc.defs @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ +/* + * Abstract: + * MiG definitions file for Mach exception interface. + */ + +subsystem +#if KERNEL_USER + KernelUser +#endif +#if KERNEL_SERVER + KernelServer +#endif /* KERNEL_SERVER */ + + mach_exc 2405; + +#include <mach/std_types.defs> +#include <mach/mach_types.defs> + +ServerPrefix catch_; + +type mach_exception_data_t = array[*:2] of int64_t; +type exception_type_t = int; + +routine mach_exception_raise( + exception_port : mach_port_t; + thread : mach_port_t; + task : mach_port_t; + exception : exception_type_t; + code : mach_exception_data_t +#if MACH_EXC_SERVER_SECTOKEN + ; + ServerSecToken stoken : security_token_t +#endif +#if MACH_EXC_SERVER_AUDITTOKEN + ; + ServerAuditToken atoken: audit_token_t +#endif + ); + +routine mach_exception_raise_state( + exception_port : mach_port_t; + exception : exception_type_t; + code : mach_exception_data_t, const; + inout flavor : int; + old_state : thread_state_t, const; + out new_state : thread_state_t +#if MACH_EXC_SERVER_SECTOKEN + ; + ServerSecToken stoken : security_token_t +#endif +#if MACH_EXC_SERVER_AUDITTOKEN + ; + ServerAuditToken atoken: audit_token_t +#endif + ); + +routine mach_exception_raise_state_identity( + exception_port : mach_port_t; + thread : mach_port_t; + task : mach_port_t; + exception : exception_type_t; + code : mach_exception_data_t; + inout flavor : int; + old_state : thread_state_t; + out new_state : thread_state_t +#if MACH_EXC_SERVER_SECTOKEN + ; + ServerSecToken stoken : security_token_t +#endif +#if MACH_EXC_SERVER_AUDITTOKEN + ; + ServerAuditToken atoken: audit_token_t +#endif + ); + +/* vim: set ft=c : */ diff --git a/util/BUILD.gn b/util/BUILD.gn index 10ca3a55..5bfe39e4 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -42,7 +42,10 @@ if (crashpad_is_mac || crashpad_is_ios) { "mach/child_port.defs", ] } else if (crashpad_is_ios) { - sources = [ "../third_party/xnu/osfmk/mach/exc.defs" ] + sources = [ + "../third_party/xnu/osfmk/mach/exc.defs", + "../third_party/xnu/osfmk/mach/mach_exc.defs", + ] } outputs = [ From 1bfd7d06ed6080861a23206e65ecd65c5b56c10f Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 21 Apr 2020 11:56:57 -0400 Subject: [PATCH 388/401] ios: Run mig with the correct SDK and architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mig was being invoked without any -arch argument, causing it to assume the build system’s native architecture, which would be x86_64. This is not correct for iOS device builds, which use arm64. The -arch argument must be plumbed to mig for correct behavior. When building for iOS, mig was being invoked without any -isysroot argument, causing it to use the root for the build system, which runs macOS and not iOS. The macOS SDK doesn’t include the ARM definitions needed for iOS device builds. <mach/exc.defs> and <mach/mach_exc.defs> depend on a small number of other .defs files to provide definitions of standard types. All .defs files are absent from the iOS SDK. These .defs files are borrowed from xnu and placed in third_party/xnu. An additional --include argument is added to allow mig to locate these files. Bug: crashpad:31 Change-Id: I27154310352939ebe2fb6329bbbfda701c369289 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2159291 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- third_party/xnu/README.crashpad | 3 + third_party/xnu/osfmk/mach/mach_types.defs | 652 ++++++++++++++++++ .../xnu/osfmk/mach/machine/machine_types.defs | 130 ++++ third_party/xnu/osfmk/mach/std_types.defs | 150 ++++ util/BUILD.gn | 45 +- util/mach/mig.py | 2 +- util/mach/mig_gen.py | 7 +- 7 files changed, 979 insertions(+), 10 deletions(-) create mode 100644 third_party/xnu/osfmk/mach/mach_types.defs create mode 100644 third_party/xnu/osfmk/mach/machine/machine_types.defs create mode 100644 third_party/xnu/osfmk/mach/std_types.defs diff --git a/third_party/xnu/README.crashpad b/third_party/xnu/README.crashpad index 813f9886..f8471d38 100644 --- a/third_party/xnu/README.crashpad +++ b/third_party/xnu/README.crashpad @@ -19,4 +19,7 @@ Local Modifications: cpu_subtype_t, and vm_prot_t types. - osfmk/mach/exc.defs and osfmk/mach/mach_exc.defs are present, to fill in for <mach/exc.defs> and <mach/mach_exc.defs> on iOS, where they are missing. + The .defs files they depend on, <mach/mach_types.defs>, + <mach/machine/machine_types.defs>, and <mach/std_types.defs> are also + included. - Anything not listed above is omitted. diff --git a/third_party/xnu/osfmk/mach/mach_types.defs b/third_party/xnu/osfmk/mach/mach_types.defs new file mode 100644 index 00000000..d2e9fb0b --- /dev/null +++ b/third_party/xnu/osfmk/mach/mach_types.defs @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2000-2016 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * NOTICE: This file was modified by McAfee Research in 2004 to introduce + * support for mandatory and extensible security protections. This notice + * is included in support of clause 2.2 (b) of the Apple Public License, + * Version 2.0. + */ +/* + */ +/* + * Mach kernel interface type declarations + */ + +#ifndef _MACH_MACH_TYPES_DEFS_ +#define _MACH_MACH_TYPES_DEFS_ + + +#include <mach/std_types.defs> + +type memory_object_offset_t = uint64_t; +type memory_object_size_t = uint64_t; +type memory_object_cluster_size_t = uint32_t; +type memory_object_fault_info_t = array[16] of integer_t; + +#ifdef KERNEL_PRIVATE + +/* Universal Page Lists - restricted to (in-kernel) pagers for now */ +type upl_size_t = uint32_t; +type upl_offset_t = uint32_t; +type upl_page_info_t = struct[2] of integer_t; +type upl_page_info_array_t = array[*:256] of upl_page_info_t; + +type upl_t = mach_port_t + intran: upl_t convert_port_to_upl(mach_port_t) + outtran: mach_port_t convert_upl_to_port(upl_t) + destructor: upl_deallocate(upl_t) + ; + +#endif /* KERNEL_PRIVATE */ + +type mach_port_status_t = struct[10] of integer_t; /* obsolete */ +type mach_port_info_ext_t = struct[17] of integer_t; + + /* mach_port_info_t: can hold either a + * mach_port_status_t (9 ints) or a + * mach_port_limits_t (1 int) or a + * mach_port_info_ext_t (17 ints). If new flavors of + * mach_port_{get,set}_attributes are added, the size of + * this array may have to be increased. (See mach/port.h) + */ +type mach_port_flavor_t = int; +type mach_port_info_t = array[*:17] of integer_t; + + /* + * mach_msg_max_trailer_t: can hold + * mach_msg_trailer_type_t (1 int) + * mach_msg_trailer_size_t (1 int) + * mach_port_seqno_t (1 int) + * security_token_t (2 ints) + * audit_token_t (8 ints) + * mach_port_context_t (2 ints) + * msgh_ad (1 int) + * msg_labels_t (1 int) + */ +type mach_msg_trailer_type_t = int; +type mach_msg_trailer_info_t = array[*:68] of char; + +type task_t = mach_port_t +#if KERNEL_SERVER + intran: task_t convert_port_to_task(mach_port_t) + outtran: mach_port_t convert_task_to_port(task_t) + destructor: task_deallocate(task_t) +#endif /* KERNEL_SERVER */ + ; + +type task_name_t = mach_port_t +#if KERNEL_SERVER + intran: task_name_t convert_port_to_task_name(mach_port_t) + outtran: mach_port_t convert_task_name_to_port(task_name_t) + destructor: task_name_deallocate(task_name_t) +#endif /* KERNEL_SERVER */ + ; + +type task_inspect_t = mach_port_t +#if KERNEL_SERVER + intran: task_inspect_t convert_port_to_task_inspect(mach_port_t) + outtran: mach_port_t convert_task_inspect_to_port(task_inspect_t) + destructor: task_inspect_deallocate(task_inspect_t) +#endif /* KERNEL_SERVER */ + ; + +type thread_t = mach_port_t +#if KERNEL_SERVER + intran: thread_t convert_port_to_thread(mach_port_t) + outtran: mach_port_t convert_thread_to_port(thread_t) + destructor: thread_deallocate(thread_t) +#endif /* KERNEL_SERVER */ + ; + +type thread_inspect_t = mach_port_t +#if KERNEL_SERVER + intran: thread_inspect_t convert_port_to_thread_inspect(mach_port_t) + outtran: mach_port_t convert_thread_inspect_to_port(thread_inspect_t) + destructor: thread_inspect_deallocate(thread_inspect_t) +#endif /* KERNEL_SERVER */ + ; + +type thread_act_t = mach_port_t +#if KERNEL_SERVER + intran: thread_act_t convert_port_to_thread(mach_port_t) + outtran: mach_port_t convert_thread_to_port(thread_act_t) + destructor: thread_deallocate(thread_act_t) +#endif /* KERNEL_SERVER */ + ; + +type thread_act_consume_ref_t = mach_port_move_send_t + cusertype: thread_act_t +#if KERNEL_SERVER + intran: thread_act_t convert_port_to_thread(mach_port_t) + destructor: thread_deallocate(thread_act_t) +#endif /* KERNEL_SERVER */ + ; + + /* thread_state_t: This inline array can hold + * a machine-dependent amount of data, defined in + * mach/machine/???? (currently THREAD_STATE_MAX, + * in mach/thread_state.h) + */ +#include <mach/machine/thread_state.h> +type thread_state_flavor_t = int; +type thread_state_t = array[*:THREAD_STATE_MAX] of natural_t; + +type task_array_t = ^array[] of task_t; +type thread_array_t = ^array[] of thread_t; +type thread_act_array_t = ^array[] of thread_act_t; +type act_params_t = array[6] of int; + +type vm_map_t = mach_port_t +#if KERNEL_SERVER + intran: vm_map_t convert_port_to_map(mach_port_t) + destructor: vm_map_deallocate(vm_map_t) +#endif /* KERNEL_SERVER */ + ; + +type vm_task_entry_t = mach_port_t + cusertype: vm_map_t +#if KERNEL_SERVER + intran: vm_map_t convert_port_entry_to_map(mach_port_t) + destructor: vm_map_deallocate(vm_map_t) +#endif /* KERNEL_SERVER */ + ; + +type ipc_space_t = mach_port_t +#if KERNEL_SERVER + intran: ipc_space_t convert_port_to_space(mach_port_t) + destructor: space_deallocate(ipc_space_t) +#endif /* KERNEL_SERVER */ + ; + +type ipc_space_inspect_t = mach_port_t +#if KERNEL_SERVER + intran: ipc_space_inspect_t convert_port_to_space_inspect(mach_port_t) + destructor: space_inspect_deallocate(ipc_space_inspect_t) +#endif /* KERNEL_SERVER */ + ; + +type arcade_register_t = mach_port_t +#if KERNEL_SERVER + intran: arcade_register_t convert_port_to_arcade_register(mach_port_t) +#endif /* KERNEL_SERVER */ + ; + +type vm_prot_t = int; +type vm_inherit_t = int; +type vm_purgable_t = int; +type xxx_vm_statistics_data_t = struct[13] of integer_t; +type vm_behavior_t = int; +type vm_statistics_data_t = struct[15] of integer_t; +type vm_machine_attribute_t = int; +type vm_machine_attribute_val_t = int; +type vm_sync_t = int; + + /* thread_info_t: this inline array can hold any of: + * thread_basic_info_t (10 ints) + * policy_timeshare_info_t (5 ints) + * policy_fifo_info_t (4 ints) + * policy_rr_info_t (5 ints) + * thread_extended_info (12 ints + 64 chars) + * if other thread_info flavors are added, this + * definition may need to be changed. (See + * mach/thread_info.h and mach/policy.h) */ +type thread_flavor_t = int; +type thread_info_t = array[*:32] of integer_t; + +type thread_policy_flavor_t = natural_t; +type thread_policy_t = array[*:16] of integer_t; + + /* task_info_t: this inline array can hold any of: + * task_basic_info_32_t (8 ints) + * task_basic_info_64_t (10 ints) + * task_events_info_t (8 ints) + * task_thread_times_info_t (4 ints) + * policy_timeshare_info_t (5 ints) + * policy_fifo_info_t (4 ints) + * policy_rr_info_t (5 ints) + * task security token (2 ints) + * task audit token (8 ints) + * dyld info (2 64-bit ints and 1 int) + * task_extmod_info_t (8 64-bit ints) + * task_basic_info_64_2_t + * mach_task_basic_info_t (12 ints) + * task_power_info_t (18 ints) + * task_vm_info_t (87 ints) + * If other task_info flavors are added, this + * definition may need to be changed. (See + * mach/task_info.h and mach/policy.h) */ +type task_flavor_t = int; +type task_info_t = array[*:87] of integer_t; + +type task_purgable_info_t = struct[68] of integer_t; + +type task_policy_flavor_t = natural_t; +type task_policy_t = array[*:16] of integer_t; + +type task_inspect_flavor_t = natural_t; +type task_inspect_info_t = array[*:4] of integer_t; + +type task_exc_guard_behavior_t = uint32_t; + +type mem_entry_name_port_t = mach_port_t +#if KERNEL_SERVER + intran: mem_entry_name_port_t null_conversion(mach_port_t) + outtran: mach_port_t null_conversion(mem_entry_name_port_t) +#endif /* KERNEL_SERVER */ + ; + +type mem_entry_name_port_move_send_t = mach_port_move_send_t + cusertype: mem_entry_name_port_t +#if KERNEL_SERVER + intran: mem_entry_name_port_t null_conversion(mach_port_t) + outtran: mach_port_t null_conversion(mem_entry_name_port_t) +#endif /* KERNEL_SERVER */ + ; + +type memory_object_default_t = mach_port_t +#if KERNEL_PRIVATE + intran: memory_object_default_t null_conversion(mach_port_t) + outtran: mach_port_t null_conversion(memory_object_default_t) +#endif /* KERNEL_PRIVATE */ + ; + +type memory_object_t = mach_port_t +#if KERNEL_PRIVATE + intran: memory_object_t convert_port_to_memory_object(mach_port_t) + outtran: mach_port_t convert_memory_object_to_port(memory_object_t) +#endif /* KERNEL_PRIVATE */ + ; + + +type memory_object_control_t = mach_port_t +#if KERNEL_PRIVATE + intran: memory_object_control_t convert_port_to_mo_control(mach_port_t) + outtran: mach_port_t convert_mo_control_to_port(memory_object_control_t) + destructor: memory_object_control_deallocate(memory_object_control_t) +#endif /* KERNEL_PRIVATE */ + ; + +type memory_object_name_t = mach_port_t + ctype: mach_port_t + ; + + +type memory_object_copy_strategy_t = int; +type memory_object_return_t = int; + +type machine_info_data_t = struct[5] of integer_t; +type machine_slot_data_t = struct[8] of integer_t; + +type host_t = mach_port_t +#if KERNEL_SERVER + intran: host_t convert_port_to_host(mach_port_t) + outtran: mach_port_t convert_host_to_port(host_t) +#endif /* KERNEL_SERVER */ + ; + +type host_priv_t = mach_port_t +#if KERNEL_SERVER + intran: host_priv_t convert_port_to_host_priv(mach_port_t) +#endif /* KERNEL_SERVER */ + ; + +type host_security_t = mach_port_t +#if KERNEL_SERVER + intran: host_security_t convert_port_to_host_security(mach_port_t) +#endif /* KERNEL_SERVER */ + ; + + /* + * host_info_t: variable-sized inline array that can contain: + * + * host_basic_info_old_t (5 ints) + * host_basic_info_t (12 ints) + * host_sched_info_t (2 ints) + * kernel_resource_sizes_t (5 ints) + * host_load_info_t (6 ints) + * vm_statistics32_t (15 ints) + * host_purgable_info_t (68 ints) + * host_expired_task_info uses a task_power_info (18 ints) + * + * If other host_info flavors are added, this definition may + * need to be changed. (See mach/{host_info,vm_statistics}.h) + */ +type host_flavor_t = int; +type host_info_t = array[*:68] of integer_t; + /* + * host_info64_t: variable-sized inline array that can contain: + * + * vm_statistics_t (6 ints and 9 longs) + * vm_extmod_statistics_t (6 64-bit ints) + */ +type host_info64_t = array[*:256] of integer_t; + +type processor_t = mach_port_t +#if KERNEL_SERVER + intran: processor_t convert_port_to_processor(mach_port_t) + outtran: mach_port_t convert_processor_to_port(processor_t) +#endif /* KERNEL_SERVER */ + ; + +type processor_array_t = ^array[] of processor_t; + + /* + * processor_info_t: variable-sized inline array that can + * contain: + * + * - processor_basic_info_t: (5 ints) + * - processor_cpu_load_info_t: (4 ints) + * - processor_machine_info_t: (12 ints) + * - processor_cpu_stat_t: (10 ints) + * - processor_cpu_stat64_t: (20 ints) + * + * If other processor_info flavors are added, this definition + * may need to be changed. + * + * See mach/processor_info.h and mach/arm/processor_info.h. + */ + +type processor_flavor_t = int; +type processor_info_t = array[*:20] of integer_t; +type processor_info_array_t = ^array[] of integer_t; + +type processor_set_t = mach_port_t +#if KERNEL_SERVER + intran: processor_set_t convert_port_to_pset(mach_port_t) + outtran: mach_port_t convert_pset_to_port(processor_set_t) + destructor: pset_deallocate(processor_set_t) +#endif /* KERNEL_SERVER */ + ; + +type processor_set_array_t = ^array[] of processor_set_t; + +type processor_set_name_t = mach_port_t +#if KERNEL_SERVER + intran: processor_set_name_t convert_port_to_pset_name(mach_port_t) + outtran: mach_port_t convert_pset_name_to_port(processor_set_name_t) + destructor: pset_deallocate(processor_set_name_t) +#endif /* KERNEL_SERVER */ + ; + +type processor_set_name_array_t = ^array[] of processor_set_name_t; + + /* processor_set_info_t: variable-size inline array + * that can hold: + * processor_set_basic_info (5 ints) + * processor_set_load_info (4 ints) + * policy_timeshare_base_t (1 int) + * policy_fifo_base_t (1 int) + * policy_rr_base_t (1 int) + * policy_timeshare_base_t (1 int) + * policy_fifo_base_t (1 int) + * policy_rr_base_t (1 int) + * policy_t (1 int) + * If other flavors are added, this definition may + * need to be changed. (see mach/processor.h) */ +type processor_set_flavor_t = int; +type processor_set_info_t = array[*:5] of integer_t; + +type bootstrap_t = mach_port_t; + +type kernel_version_t = c_string[*:512]; +type kernel_boot_info_t = c_string[*:4096]; + +type time_value_t = struct[2] of integer_t; + +type mach_port_qos_t = struct[2] of integer_t; + +type mach_port_options_t = struct[3] of uint64_t; +type mach_port_options_ptr_t = ^ mach_port_options_t; + +type emulation_vector_t = ^array[] of vm_offset_t; + +type inline_existence_map_t = array[*:512] of char; + +type policy_t = int; + /* policy_info_t: variable-size inline array. Can hold: + * policy_timeshare_info_t (5 ints) + * policy_fifo_info_t (4 ints) + * policy_rr_info_t (5 ints) */ +type policy_base_t = array[*:5] of integer_t; +type policy_info_t = array[*:2] of integer_t; +type policy_limit_t = array[*:1] of integer_t; + +type ledger_t = mach_port_t +#if KERNEL_SERVER + intran: ledger_t convert_port_to_ledger(mach_port_t) + outtran: mach_port_t convert_ledger_to_port(ledger_t) +#endif /* KERNEL_SERVER */ + ; + +type ledger_array_t = ^array[] of ledger_t; +type ledger_item_t = integer_t; + /* DEPRECATED */ + +type ledger_amount_t = int64_t; + +type security_token_t = struct[2] of uint32_t; +type audit_token_t = struct[8] of uint32_t; + +type msg_labels_t = mach_port_t; + + /* memory_object_info_t: variable-size inline array: + * memory_object_attr_info_t (5 ints) + * XXX actually it's 6 ints temporarily (object_ready!) + * memory_object_behave_info_t (4 ints) + * memory_object_perf_info_t (2 ints) + * old_memory_object_attr_info_t (3 ints) + * If other flavors are added, this definition may + * need to be changed. (see mach/memory_object.h) */ +type memory_object_flavor_t = int; +type memory_object_info_t = array[*:6] of int; + + /* vm_region_info_t: variable-size inline array that can hold: + * vm_region_basic_info_t (8 ints) + * If other flavors are added, this definition may + * need to be changed. (see mach/vm_region.h) */ +type vm_region_flavor_t = int; +type vm_region_info_t = array[*:10] of int; +type vm_region_recurse_info_t = array[*:19] of int; + +type vm_page_info_flavor_t = int; +type vm_page_info_t = array[*:32] of int; + +type mach_vm_read_entry_t = array[512] of mach_vm_offset_t; +type vm_read_entry_t = array[512] of vm_offset_t; +#ifdef VM32_SUPPORT +type vm32_read_entry_t = array[512] of vm32_offset_t; +#endif + +type exception_mask_t = int; +type exception_behavior_t = int; + +type exception_handler_t = mach_port_t; + +type exception_handler_array_t = + array[*:32] of exception_handler_t; + +type exception_behavior_array_t = + array[*:32] of exception_behavior_t; + +type exception_flavor_array_t = + array[*:32] of thread_state_flavor_t; + +type exception_mask_array_t = + array[*:32] of exception_mask_t; + +type semaphore_t = mach_port_t +#if KERNEL_SERVER + intran: semaphore_t convert_port_to_semaphore(mach_port_t) + outtran: mach_port_t convert_semaphore_to_port(semaphore_t) + destructor: semaphore_dereference(semaphore_t) +#endif /* KERNEL_SERVER */ + ; + +type semaphore_consume_ref_t = mach_port_move_send_t + cusertype: semaphore_t +#if KERNEL_SERVER + intran: semaphore_t convert_port_to_semaphore(mach_port_t) + outtran: mach_port_t convert_semaphore_to_port(semaphore_t) +#endif /* KERNEL_SERVER */ + ; + +type lock_set_t = mach_port_t +#if KERNEL_SERVER + intran: lock_set_t convert_port_to_lock_set(mach_port_t) + outtran: mach_port_t convert_lock_set_to_port(lock_set_t) + destructor: lock_set_dereference(lock_set_t) +#endif /* KERNEL_SERVER */ + ; + +type task_suspension_token_t = mach_port_move_send_once_t +#if KERNEL_SERVER + intran: task_suspension_token_t convert_port_to_task_suspension_token(mach_port_t) + outtran: mach_port_t convert_task_suspension_token_to_port(task_suspension_token_t) +#endif /* KERNEL_SERVER */ + ; + +type vfs_path_t = c_string[4096]; +type nspace_path_t = c_string[1024]; /* 1024 == PATH_MAX */ + +/* public voucher types */ + +/* Mach voucher object */ +type mach_voucher_t = mach_port_t; +type mach_voucher_name_t = mach_port_name_t; + +type mach_voucher_attr_manager_t = mach_port_t; +type mach_voucher_attr_control_t = mach_port_t; + +/* IPC voucher internal object */ +type ipc_voucher_t = mach_port_t +#if KERNEL_SERVER + intran: ipc_voucher_t convert_port_to_voucher(mach_port_t) + outtran: mach_port_t convert_voucher_to_port(ipc_voucher_t) + destructor: ipc_voucher_release(ipc_voucher_t) +#endif /* KERNEL_SERVER */ + ; + +/* IPC voucher attribute control internal object */ +type ipc_voucher_attr_control_t = mach_port_t +#if KERNEL_SERVER + intran: ipc_voucher_attr_control_t convert_port_to_voucher_attr_control(mach_port_t) + outtran: mach_port_t convert_voucher_attr_control_to_port(ipc_voucher_attr_control_t) + destructor: ipc_voucher_attr_control_release(ipc_voucher_attr_control_t) +#endif /* KERNEL_SERVER */ + ; + +type mach_voucher_attr_key_t = uint32_t; + +type mach_voucher_attr_command_t = uint32_t; +type mach_voucher_attr_recipe_command_t = uint32_t; + +type mach_voucher_attr_content_size_t = uint32_t; +type mach_voucher_attr_content_t = array[*:4096] of uint8_t; +type mach_voucher_attr_content_array_t = array[*:5120] of uint8_t; + +type mach_voucher_attr_raw_recipe_size_t = uint32_t; +type mach_voucher_attr_raw_recipe_t = array[*:4096] of uint8_t; +type mach_voucher_attr_raw_recipe_array_t = array[*:5120] of uint8_t; + +type mach_voucher_selector_t = uint32_t; + +type mach_voucher_attr_value_handle_t = uint64_t; +type mach_voucher_attr_value_handle_array_t = array[*:4] of mach_voucher_attr_value_handle_t; +type mach_voucher_attr_value_reference_t = uint32_t; + +/* kernel module loader */ +type kmod_t = int; +type kmod_control_flavor_t = int; + +type kmod_args_t = ^array[] of MACH_MSG_TYPE_BYTE + ctype: kmod_args_t; + +type io_master_t = mach_port_t; +type UNDServerRef = mach_port_t; + +/* These must be kept in sync with definitions in osfmk/mach/dyld_kernel.h */ +type dyld_kernel_image_info_t = struct[40] of MACH_MSG_TYPE_BYTE; +type dyld_kernel_image_info_array_t = ^array[] of dyld_kernel_image_info_t; +type dyld_kernel_process_info_t = struct[64] of MACH_MSG_TYPE_BYTE; + +#if KERNEL_SERVER +#ifdef MACH_KERNEL_PRIVATE +simport <ipc/ipc_voucher.h>; /* for voucher conversions */ +simport <kern/ipc_kobject.h>; /* for null conversion */ +simport <kern/ipc_tt.h>; /* for task/thread conversion */ +simport <kern/ipc_host.h>; /* for host/processor/pset conversions */ +simport <kern/ipc_sync.h>; /* for lock_set and semaphore conversions */ +simport <kern/ledger.h>; /* for ledger conversions */ +simport <kern/processor.h>; /* for processor conversions */ +simport <kern/sync_lock.h>; /* for lock-set conversions */ +simport <kern/sync_sema.h>; /* for semaphore conversions */ +simport <vm/memory_object.h>; /* for memory object type conversions */ +simport <vm/vm_map.h>; /* for vm_map conversions */ +#if CONFIG_ARCADE +simport <kern/arcade.h>; /* for arcade_register conversions */ +#endif +#endif /* MACH_KERNEL_PRIVATE */ + +simport <kern/ipc_mig.h>; /* pick up kernel-specific MIG things */ + +#endif /* KERNEL_SERVER */ + +import <mach/mig.h>; +import <mach/mach_types.h>; + +#endif /* _MACH_MACH_TYPES_DEFS_ */ + +/* vim: set ft=c : */ diff --git a/third_party/xnu/osfmk/mach/machine/machine_types.defs b/third_party/xnu/osfmk/mach/machine/machine_types.defs new file mode 100644 index 00000000..f4813948 --- /dev/null +++ b/third_party/xnu/osfmk/mach/machine/machine_types.defs @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2000-2007 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ + +/* + * Header file for basic, machine-dependent data types. arm+i386 version. + */ + +#ifndef _MACH_MACHINE_MACHNINE_TYPES_DEFS +#define _MACH_MACHINE_MACHNINE_TYPES_DEFS + +type short = int16_t; +type int = int32_t; +type unsigned = uint32_t; + +type float = MACH_MSG_TYPE_REAL_32; +type double = MACH_MSG_TYPE_REAL_64; + + +/* from ISO/IEC 988:1999 spec */ +/* 7.18.1.4 Integer types capable of hgolding object pointers */ +/* + * The [u]intptr_t types for the native + * integer type, e.g. 32 or 64 or.. whatever + * register size the machine has. They are + * used for entities that might be either + * [unsigned] integers or pointers, and for + * type-casting between the two. + * + * For instance, the IPC system represents + * a port in user space as an integer and + * in kernel space as a pointer. + */ +#if defined(__LP64__) +type uintptr_t = uint64_t; +type intptr_t = int64_t; +#else +type uintptr_t = uint32_t; +type intptr_t = int32_t; +#endif + +/* + * These are the legacy Mach types that are + * the [rough] equivalents of the standards above. + * They were defined in terms of int, not + * long int, so they remain separate. + */ +#if defined(__LP64__) +type register_t = int64_t; +#else +type register_t = int32_t; +#endif +type integer_t = int32_t; +type natural_t = uint32_t; + +/* + * These are the VM types that scale with the address + * space size of a given process. + */ + +#if defined(__LP64__) +type vm_address_t = uint64_t; +type vm_offset_t = uint64_t; +type vm_size_t = uint64_t; +#else +type vm_address_t = natural_t; +type vm_offset_t = natural_t; +type vm_size_t = natural_t; +#endif + +/* This is a bit of a hack for arm. We implement the backend with a wide type, but present a native-sized type to callers */ +type mach_port_context_t = uint64_t; + +/* + * The mach_vm_xxx_t types are sized to hold the + * maximum pointer, offset, etc... supported on the + * platform. + */ +type mach_vm_address_t = uint64_t; +type mach_vm_offset_t = uint64_t; +type mach_vm_size_t = uint64_t; + +#if MACH_IPC_COMPAT +/* + * For the old IPC interface + */ +#define MSG_TYPE_PORT_NAME natural_t + +#endif /* MACH_IPC_COMPAT */ + +/* + * These are types used internal to Mach to implement the + * legacy 32-bit VM APIs published by the kernel. + */ +#define VM32_SUPPORT 1 + +type vm32_address_t = uint32_t; +type vm32_offset_t = uint32_t; +type vm32_size_t = uint32_t; + +#endif /* _MACH_MACHINE_MACHNINE_TYPES_DEFS */ + +/* vim: set ft=c : */ diff --git a/third_party/xnu/osfmk/mach/std_types.defs b/third_party/xnu/osfmk/mach/std_types.defs new file mode 100644 index 00000000..0b483836 --- /dev/null +++ b/third_party/xnu/osfmk/mach/std_types.defs @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ +/* + * Mach kernel standard interface type declarations + */ + +#ifndef _MACH_STD_TYPES_DEFS_ +#define _MACH_STD_TYPES_DEFS_ + +/* from ISO/IEC 988:1999 spec */ +/* 7.18.1.1 Exact-width integer types */ + +type int8_t = MACH_MSG_TYPE_INTEGER_8; +type uint8_t = MACH_MSG_TYPE_INTEGER_8; +type int16_t = MACH_MSG_TYPE_INTEGER_16; +type uint16_t = MACH_MSG_TYPE_INTEGER_16; +type int32_t = MACH_MSG_TYPE_INTEGER_32; +type uint32_t = MACH_MSG_TYPE_INTEGER_32; +type int64_t = MACH_MSG_TYPE_INTEGER_64; +type uint64_t = MACH_MSG_TYPE_INTEGER_64; + +/* + * Legacy fixed-length Mach types which should + * be replaced with the Standard types from above. + */ +type int32 = int32_t; +type unsigned32 = uint32_t; +type int64 = int64_t; +type unsigned64 = uint64_t; + +/* + * Other fixed length Mach types. + */ +type char = MACH_MSG_TYPE_CHAR; +type boolean_t = MACH_MSG_TYPE_BOOLEAN; + +#include <mach/machine/machine_types.defs> + +type kern_return_t = int; + +type pointer_t = ^array[] of MACH_MSG_TYPE_BYTE + ctype: vm_offset_t; + + +type mach_port_t = MACH_MSG_TYPE_COPY_SEND; +type mach_port_array_t = array[] of mach_port_t; + +type mach_port_name_t = MACH_MSG_TYPE_PORT_NAME; +type mach_port_name_array_t = array[] of mach_port_name_t; + +type mach_port_right_t = natural_t; + +type mach_port_type_t = natural_t; +type mach_port_type_array_t = array[] of mach_port_type_t; + +type mach_port_urefs_t = natural_t; +type mach_port_delta_t = integer_t; +type mach_port_seqno_t = natural_t; +type mach_port_mscount_t = unsigned; +type mach_port_msgcount_t = unsigned; +type mach_port_rights_t = unsigned; +type mach_msg_id_t = integer_t; +type mach_msg_size_t = natural_t; +type mach_msg_type_name_t = unsigned; +type mach_msg_options_t = integer_t; + +type mach_port_move_receive_t = MACH_MSG_TYPE_MOVE_RECEIVE + ctype: mach_port_t; +type mach_port_copy_send_t = MACH_MSG_TYPE_COPY_SEND + ctype: mach_port_t; +type mach_port_make_send_t = MACH_MSG_TYPE_MAKE_SEND + ctype: mach_port_t; +type mach_port_move_send_t = MACH_MSG_TYPE_MOVE_SEND + ctype: mach_port_t; +type mach_port_make_send_once_t = MACH_MSG_TYPE_MAKE_SEND_ONCE + ctype: mach_port_t; +type mach_port_move_send_once_t = MACH_MSG_TYPE_MOVE_SEND_ONCE + ctype: mach_port_t; + +type mach_port_receive_t = MACH_MSG_TYPE_PORT_RECEIVE + ctype: mach_port_t; +type mach_port_send_t = MACH_MSG_TYPE_PORT_SEND + ctype: mach_port_t; +type mach_port_send_once_t = MACH_MSG_TYPE_PORT_SEND_ONCE + ctype: mach_port_t; + +type mach_port_poly_t = polymorphic + ctype: mach_port_t; + +import <mach/std_types.h>; +import <mach/mig.h>; + +#endif /* _MACH_STD_TYPES_DEFS_ */ + +/* vim: set ft=c : */ diff --git a/util/BUILD.gn b/util/BUILD.gn index 5bfe39e4..d7c1b132 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -23,16 +23,18 @@ if (crashpad_is_in_chromium) { } if (crashpad_is_mac || crashpad_is_ios) { - if (crashpad_is_mac) { - if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { - import("//build/config/sysroot.gni") - } else { - import("//third_party/mini_chromium/mini_chromium/build/sysroot.gni") - } + if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { + import("//build/config/sysroot.gni") + } else { + import("//third_party/mini_chromium/mini_chromium/build/sysroot.gni") } action_foreach("mig") { script = "mach/mig.py" + inputs = [ + "mach/mig_fix.py", + "mach/mig_gen.py", + ] if (crashpad_is_mac) { sources = [ @@ -43,6 +45,7 @@ if (crashpad_is_mac || crashpad_is_ios) { ] } else if (crashpad_is_ios) { sources = [ + # The iOS SDK doesn’t have any .defs files. Get them directly from xnu. "../third_party/xnu/osfmk/mach/exc.defs", "../third_party/xnu/osfmk/mach/mach_exc.defs", ] @@ -76,7 +79,7 @@ if (crashpad_is_mac || crashpad_is_ios) { ] } } - if (!crashpad_is_ios && sysroot != "") { + if (sysroot != "") { args += [ "--sdk", sysroot, @@ -86,6 +89,34 @@ if (crashpad_is_mac || crashpad_is_ios) { "--include", rebase_path("../compat/mac", root_build_dir), ] + if (crashpad_is_ios) { + args += [ + # The iOS SDK doesn’t have any .defs files. Get them directly from xnu. + "--include", + rebase_path("../third_party/xnu/osfmk", root_build_dir), + ] + } + if (current_cpu == "x86") { + args += [ + "--arch", + "i386", + ] + } else if (current_cpu == "x64") { + args += [ + "--arch", + "x86_64", + ] + } else if (current_cpu == "arm") { + args += [ + "--arch", + "armv7", + ] + } else if (current_cpu == "arm64") { + args += [ + "--arch", + "arm64", + ] + } } source_set("mig_output") { diff --git a/util/mach/mig.py b/util/mach/mig.py index ef14031c..dc9b7c64 100755 --- a/util/mach/mig.py +++ b/util/mach/mig.py @@ -27,7 +27,7 @@ def main(args): parsed.user_h, parsed.server_h) mig_gen.generate_interface(parsed.defs, interface, parsed.include, parsed.sdk, parsed.clang_path, parsed.mig_path, - parsed.migcom_path) + parsed.migcom_path, parsed.arch) mig_fix.fix_interface(interface) if __name__ == '__main__': diff --git a/util/mach/mig_gen.py b/util/mach/mig_gen.py index 976cd126..b3e9a5b4 100755 --- a/util/mach/mig_gen.py +++ b/util/mach/mig_gen.py @@ -25,7 +25,7 @@ MigInterface = collections.namedtuple('MigInterface', ['user_c', 'server_c', 'user_h', 'server_h']) def generate_interface(defs, interface, includes=[], sdk=None, clang_path=None, - mig_path=None, migcom_path=None): + mig_path=None, migcom_path=None, arch=None): if mig_path is None: mig_path = 'mig' command = [mig_path, @@ -39,6 +39,8 @@ def generate_interface(defs, interface, includes=[], sdk=None, clang_path=None, os.environ['MIGCC'] = clang_path if migcom_path is not None: os.environ['MIGCOM'] = migcom_path + if arch is not None: + command.extend(['-arch', arch]) if sdk is not None: command.extend(['-isysroot', sdk]) for include in includes: @@ -51,6 +53,7 @@ def parse_args(args): parser.add_argument('--clang-path', help='Path to Clang') parser.add_argument('--mig-path', help='Path to mig') parser.add_argument('--migcom-path', help='Path to migcom') + parser.add_argument('--arch', help='Target architecture') parser.add_argument('--sdk', help='Path to SDK') parser.add_argument('--include', default=[], @@ -69,7 +72,7 @@ def main(args): parsed.user_h, parsed.server_h) generate_interface(parsed.defs, interface, parsed.include, parsed.sdk, parsed.clang_path, parsed.mig_path, - parsed.migcom_path) + parsed.migcom_path, parsed.arch) if __name__ == '__main__': sys.exit(main(sys.argv[1:])) From 64b8791f4523bbae346b35bd5bf34b80f4431e49 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Tue, 21 Apr 2020 11:59:44 -0400 Subject: [PATCH 389/401] ios: Build util/mach/exc_server_variants.cc, support code, and tests This makes UniversalMachExcServer available on iOS. UniversalMachExcServer is the foundation for a Mach exc and mach_exc server. Some code in UniversalMachExcServer needs to be evaluated to ensure that portions that run in the same process that has sustained the exception are safe to do so at that time. For example, SimplifiedExcServer<ExcTraits>::Interface instantiates and appends to a std::vector<>, which is generally unsafe in this context. However, that code responds to exc requests. The mach_exc equivalent, SimplifiedMachExcServer<MachExcTraits>::Interface, does not use a vector at all. This also enables support code in the form of CompositeMachMessageServer and UniversalExceptionRaise, all of the tests for CompositeMachMessageServer, and most of the test for exc_server_variants.cc. The multiprocess-based exc_server_variants tests remain disabled on iOS. Bug: crashpad:31 Change-Id: I838ed770a33ca29c37383c32245eb340fb3ad2fb Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2159287 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- util/BUILD.gn | 16 ++++++++-------- util/mach/exc_server_variants.cc | 3 ++- util/mach/exc_server_variants_test.cc | 14 +++++++++++++- util/mach/mach_extensions.cc | 4 ++-- util/mach/mach_extensions_test.cc | 4 ++-- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/util/BUILD.gn b/util/BUILD.gn index d7c1b132..c924b93e 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -288,6 +288,12 @@ static_library("util") { sources += [ "mac/xattr.cc", "mac/xattr.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", @@ -320,12 +326,6 @@ static_library("util") { "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_types.cc", "mach/exception_types.h", "mach/notify_server.cc", @@ -704,6 +704,8 @@ source_set("util_test") { if (crashpad_is_mac || crashpad_is_ios) { sources += [ "mac/xattr_test.cc", + "mach/composite_mach_message_server_test.cc", + "mach/exc_server_variants_test.cc", "mach/exception_behaviors_test.cc", "mach/mach_extensions_test.cc", "mach/mach_message_test.cc", @@ -718,9 +720,7 @@ source_set("util_test") { "mach/bootstrap_test.cc", "mach/child_port_handshake_test.cc", "mach/child_port_server_test.cc", - "mach/composite_mach_message_server_test.cc", "mach/exc_client_variants_test.cc", - "mach/exc_server_variants_test.cc", "mach/exception_ports_test.cc", "mach/exception_types_test.cc", "mach/mach_message_server_test.cc", diff --git a/util/mach/exc_server_variants.cc b/util/mach/exc_server_variants.cc index 6264cb33..c272ae72 100644 --- a/util/mach/exc_server_variants.cc +++ b/util/mach/exc_server_variants.cc @@ -22,6 +22,7 @@ #include "base/logging.h" #include "base/stl_util.h" +#include "build/build_config.h" #include "util/mac/mac_util.h" #include "util/mach/composite_mach_message_server.h" #include "util/mach/exc.h" @@ -682,7 +683,7 @@ kern_return_t ExcServerSuccessfulReturnValue(exception_type_t exception, exception_behavior_t behavior, bool set_thread_state) { if (exception == EXC_CRASH -#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11 +#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11 && MacOSXMinorVersion() >= 11 #endif ) { diff --git a/util/mach/exc_server_variants_test.cc b/util/mach/exc_server_variants_test.cc index 078d4aed..bea3d767 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -25,13 +25,16 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include "test/mac/mach_errors.h" -#include "test/mac/mach_multiprocess.h" #include "util/mac/mac_util.h" #include "util/mach/exception_behaviors.h" #include "util/mach/exception_types.h" #include "util/mach/mach_message.h" #include "util/misc/implicit_cast.h" +#if !defined(OS_IOS) +#include "test/mac/mach_multiprocess.h" +#endif // !OS_IOS + namespace crashpad { namespace test { namespace { @@ -958,6 +961,8 @@ TEST(ExcServerVariants, MachMessageServerRequestIDs) { expect_request_ids); } +#if !defined(OS_IOS) + class TestExcServerVariants : public MachMultiprocess, public UniversalMachExcServer::Interface { public: @@ -1193,9 +1198,16 @@ TEST(ExcServerVariants, ThreadStates) { } } +#endif // !OS_IOS + TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) { +#if defined(OS_IOS) + // iOS 9 ≅ OS X 10.11. + const kern_return_t prefer_not_set_thread_state = KERN_SUCCESS; +#else const kern_return_t prefer_not_set_thread_state = MacOSXMinorVersion() < 11 ? MACH_RCV_PORT_DIED : KERN_SUCCESS; +#endif const struct { exception_type_t exception; diff --git a/util/mach/mach_extensions.cc b/util/mach/mach_extensions.cc index 9e310120..cefb9bf3 100644 --- a/util/mach/mach_extensions.cc +++ b/util/mach/mach_extensions.cc @@ -46,7 +46,7 @@ exception_mask_t ExcMaskAll() { // xnu-2422.110.17/osfmk/mach/ipc_tt.c. #if defined(OS_IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 -// iOS 7 ≅ macOS 10.9. +// iOS 7 ≅ OS X 10.9. #error This code was not ported to iOS versions older than 7 #endif @@ -93,7 +93,7 @@ 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 -// iOS 9 ≅ macOS 10.11. +// iOS 9 ≅ OS X 10.11. #error This code was not ported to iOS versions older than 9 #endif diff --git a/util/mach/mach_extensions_test.cc b/util/mach/mach_extensions_test.cc index 748e0aa5..9fd49402 100644 --- a/util/mach/mach_extensions_test.cc +++ b/util/mach/mach_extensions_test.cc @@ -81,7 +81,7 @@ TEST(MachExtensions, ExcMaskAll) { EXPECT_FALSE(exc_mask_all & EXC_MASK_CORPSE_NOTIFY); #if defined(OS_IOS) - // Assume at least iOS 7 (≅ macOS 10.9). + // 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 @@ -113,7 +113,7 @@ TEST(MachExtensions, ExcMaskValid) { EXPECT_TRUE(exc_mask_valid & EXC_MASK_CRASH); #if defined(OS_IOS) - // Assume at least iOS 9 (≅ macOS 10.11). + // 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); From adfd94a35798b1cfaeeac59149f7ef093f8b2ad9 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Wed, 22 Apr 2020 10:44:15 -0400 Subject: [PATCH 390/401] ios: Use compat to provide items missing from the iOS SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This updates the way that the .defs files added in 1bfd7d06ed60 are treated, by putting them in compat/ios, using compat as intended. The .defs files in compat forward, via #include, to the ones in third_party/xnu. Additionally, compat/mac is enabled for iOS, as everything in compat/mac is sensible on iOS, and will have no effect when rendered unnecessary by the iOS SDK. This also changes util:mig_output to a static_library instead of a source_set. I don’t think there was any reason for it to have been a source_set to begin with. static_library is preferred for nearly everything. Bug: crashpad:31 Change-Id: I7c468d6d6785bf2bc825d45831ebb81e1c9ddfbc Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2160310 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- compat/BUILD.gn | 23 ++++++++++++++++++---- compat/ios/mach/exc.defs | 20 +++++++++++++++++++ compat/ios/mach/mach_exc.defs | 20 +++++++++++++++++++ compat/ios/mach/mach_types.defs | 20 +++++++++++++++++++ compat/ios/mach/machine/machine_types.defs | 20 +++++++++++++++++++ compat/ios/mach/std_types.defs | 20 +++++++++++++++++++ util/BUILD.gn | 7 ++++--- 7 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 compat/ios/mach/exc.defs create mode 100644 compat/ios/mach/mach_exc.defs create mode 100644 compat/ios/mach/mach_types.defs create mode 100644 compat/ios/mach/machine/machine_types.defs create mode 100644 compat/ios/mach/std_types.defs diff --git a/compat/BUILD.gn b/compat/BUILD.gn index 2f246565..9c22acfc 100644 --- a/compat/BUILD.gn +++ b/compat/BUILD.gn @@ -17,12 +17,16 @@ import("../build/crashpad_buildconfig.gni") config("compat_config") { include_dirs = [] - if (crashpad_is_mac) { + if (crashpad_is_mac || crashpad_is_ios) { include_dirs += [ "mac" ] - } else if (!crashpad_is_ios) { + } else { include_dirs += [ "non_mac" ] } + if (crashpad_is_ios) { + include_dirs += [ "ios" ] + } + if (crashpad_is_linux || crashpad_is_android) { include_dirs += [ "linux" ] } @@ -59,15 +63,16 @@ template("compat_target") { compat_target("compat") { sources = [] - if (crashpad_is_mac) { + if (crashpad_is_mac || crashpad_is_ios) { sources += [ "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", ] - } else if (!crashpad_is_ios) { + } else { sources += [ "non_mac/mach-o/loader.h", "non_mac/mach/mach.h", @@ -76,6 +81,16 @@ compat_target("compat") { ] } + if (crashpad_is_ios) { + 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", + ] + } + if (crashpad_is_linux || crashpad_is_android) { sources += [ "linux/signal.h", diff --git a/compat/ios/mach/exc.defs b/compat/ios/mach/exc.defs new file mode 100644 index 00000000..d1648e97 --- /dev/null +++ b/compat/ios/mach/exc.defs @@ -0,0 +1,20 @@ +// 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_COMPAT_IOS_MACH_EXC_DEFS_ +#define CRASHPAD_COMPAT_IOS_MACH_EXC_DEFS_ + +#include "third_party/xnu/osfmk/mach/exc.defs" + +#endif // CRASHPAD_COMPAT_IOS_MACH_EXC_DEFS_ diff --git a/compat/ios/mach/mach_exc.defs b/compat/ios/mach/mach_exc.defs new file mode 100644 index 00000000..c562128e --- /dev/null +++ b/compat/ios/mach/mach_exc.defs @@ -0,0 +1,20 @@ +// 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_COMPAT_IOS_MACH_MACH_EXC_DEFS_ +#define CRASHPAD_COMPAT_IOS_MACH_MACH_EXC_DEFS_ + +#include "third_party/xnu/osfmk/mach/mach_exc.defs" + +#endif // CRASHPAD_COMPAT_IOS_MACH_MACH_EXC_DEFS_ diff --git a/compat/ios/mach/mach_types.defs b/compat/ios/mach/mach_types.defs new file mode 100644 index 00000000..dc18b8eb --- /dev/null +++ b/compat/ios/mach/mach_types.defs @@ -0,0 +1,20 @@ +// 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_COMPAT_IOS_MACH_MACH_TYPES_DEFS_ +#define CRASHPAD_COMPAT_IOS_MACH_MACH_TYPES_DEFS_ + +#include "third_party/xnu/osfmk/mach/mach_types.defs" + +#endif // CRASHPAD_COMPAT_IOS_MACH_MACH_TYPES_DEFS_ diff --git a/compat/ios/mach/machine/machine_types.defs b/compat/ios/mach/machine/machine_types.defs new file mode 100644 index 00000000..e906466f --- /dev/null +++ b/compat/ios/mach/machine/machine_types.defs @@ -0,0 +1,20 @@ +// 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_COMPAT_IOS_MACH_MACHINE_MACHINE_TYPES_DEFS_ +#define CRASHPAD_COMPAT_IOS_MACH_MACHINE_MACHINE_TYPES_DEFS_ + +#include "third_party/xnu/osfmk/mach/machine/machine_types.defs" + +#endif // CRASHPAD_COMPAT_IOS_MACH_MACHINE_MACHINE_TYPES_DEFS_ diff --git a/compat/ios/mach/std_types.defs b/compat/ios/mach/std_types.defs new file mode 100644 index 00000000..e49c6e46 --- /dev/null +++ b/compat/ios/mach/std_types.defs @@ -0,0 +1,20 @@ +// 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_COMPAT_IOS_MACH_STD_TYPES_DEFS_ +#define CRASHPAD_COMPAT_IOS_MACH_STD_TYPES_DEFS_ + +#include "third_party/xnu/osfmk/mach/std_types.defs" + +#endif // CRASHPAD_COMPAT_IOS_MACH_STD_TYPES_DEFS_ diff --git a/util/BUILD.gn b/util/BUILD.gn index c924b93e..f291f5b7 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -86,14 +86,15 @@ if (crashpad_is_mac || crashpad_is_ios) { ] } args += [ + "--include", + rebase_path("..", root_build_dir), "--include", rebase_path("../compat/mac", root_build_dir), ] if (crashpad_is_ios) { args += [ - # The iOS SDK doesn’t have any .defs files. Get them directly from xnu. "--include", - rebase_path("../third_party/xnu/osfmk", root_build_dir), + rebase_path("../compat/ios", root_build_dir), ] } if (current_cpu == "x86") { @@ -119,7 +120,7 @@ if (crashpad_is_mac || crashpad_is_ios) { } } - source_set("mig_output") { + static_library("mig_output") { deps = [ ":mig" ] sources = get_target_outputs(":mig") if (crashpad_is_in_chromium) { From ec105797e6cff511a8075063bde85a303d00328b Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 24 Apr 2020 08:14:41 -0700 Subject: [PATCH 391/401] Update the status page Change-Id: If9075e6cd0785e7a2c64263144db9ecafbeec9b0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2163916 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- doc/status.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/doc/status.md b/doc/status.md index dcb6e62e..3948b449 100644 --- a/doc/status.md +++ b/doc/status.md @@ -18,24 +18,27 @@ limitations under the License. ## Completed -Crashpad currently consists of a crash-reporting client and some related tools -for macOS and Windows. The core client work for both platforms is substantially -complete. Crashpad became the crash reporter client for -[Chromium](https://www.chromium.org/Home) on macOS as of [March +Crashpad has complete crash-reporting clients and some related tools for macOS, +Windows, Fuchsia, and Linux (including Android and Chromium OS). Crashpad became +the crash reporter client for [Chromium](https://www.chromium.org/Home) on macOS +as of [March 2015](https://chromium.googlesource.com/chromium/src/\+/d413b2dcb54d523811d386f1ff4084f677a6d089), -and on Windows as of [November -2015](https://chromium.googlesource.com/chromium/src/\+/cfa5b01bb1d06bf96967bd37e21a44752801948c). +Windows as of [November +2015](https://chromium.googlesource.com/chromium/src/\+/cfa5b01bb1d06bf96967bd37e21a44752801948c), +and Android as of [January +2019](https://chromium.googlesource.com/chromium/src/+/f890e4b5495ab693d2d37aec3c378239946154f7). + ## In Progress -Initial work on a Crashpad client for -[Android](https://crashpad.chromium.org/bug/30) has begun. This is currently in -the early implementation phase. +Chromium is transitioning to Crashpad for [Chromium OS and Desktop +Linux](https://crbug.com/942279). + +Work has begun on a Crashpad client for +[iOS](https://crashpad.chromium.org/bug/31). ## Future -There are plans to bring Crashpad clients to other operating systems in the -future, including a more generic non-Android Linux implementation. There are -also plans to implement a [crash report +There are also plans to implement a [crash report processor](https://crashpad.chromium.org/bug/29) as part of Crashpad. No timeline for completing this work has been set yet. From 9fea20040e8cb886294c2915e9bd186c74687cbc Mon Sep 17 00:00:00 2001 From: Joshua Peraza <jperaza@chromium.org> Date: Fri, 24 Apr 2020 10:24:53 -0700 Subject: [PATCH 392/401] linux: Update overview design Bug: crashpad:294 Change-Id: Ie84b56bd429320dab1d232d0b19c6378b7d3755a Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2165627 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org> --- doc/overview_design.md | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/doc/overview_design.md b/doc/overview_design.md index 07a7d651..9d0f0edd 100644 --- a/doc/overview_design.md +++ b/doc/overview_design.md @@ -240,7 +240,24 @@ of command line arguments in this mode. #### Linux/Android -TODO(mmentovai): describe this. See this preliminary doc. +On Linux, a registration is a connected socket pair between a client process and +the Crashpad handler. This socket pair may be private or shared among many +client processes. + +##### Private Connections + +Private connections are the default registration mode when starting the handler +process in response to a crash or on behalf of another client. This mode is +required to use a ptrace broker, which is in turn required to trace Android +isolated processes. + +##### Shared Connections + +Shared connections are the default mode when using a long-lived handler. The +same connected socket pair may be shared among any number of clients. The socket +pair is created by the first process to start the handler at which point the +client socket end may be shared with other clients by any convenient means (e.g. +inheritance). ### Capturing Exceptions @@ -290,8 +307,16 @@ here.](https://crashpad.chromium.org/bug/133) #### Linux/Android -TODO(mmentovai): describe this. See [this preliminary -doc.](https://goto.google.com/crashpad-android-dd) +On Linux, exceptions are dispatched as signals to the crashing thread. Crashpad +signal handlers will send a message over the socket to the Crashpad handler +notifying it of the crash and the location of exception information to be read +from the crashing process. When using a shared socket connection, communication +is entirely one-way. The client sends its dump request to the handler and then +waits until the handler responds with a SIGCONT or a timeout occurs. When using +a private socket connection, the handler may respond over the socket to +communicate with a ptrace broker process. The broker is forked from the crashing +process, executes ptrace requests against the crashing process, and sends the +information over the socket to the handler. ### The CrashpadInfo structure From 069fddf1843ce0bb71f98111667c15a634b0ba34 Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 24 Apr 2020 12:44:10 -0700 Subject: [PATCH 393/401] fuchsia: Remove unused sysinfo dep This was previously used, but is no longer required. Delete the one remaining include at the build rules. Change-Id: If5083a4fb8a5562d3e40149976bd27fcec0fd302 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2165635 Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Francois Rousseau <frousseau@google.com> Commit-Queue: Scott Graham <scottmg@chromium.org> --- third_party/fuchsia/BUILD.gn | 8 -------- util/fuchsia/koid_utilities.cc | 1 - 2 files changed, 9 deletions(-) diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 56d426ab..1fa174aa 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -20,7 +20,6 @@ if (crashpad_is_in_fuchsia) { "//zircon/public/lib/fdio", "//zircon/public/lib/zx", "//zircon/system/fidl/fuchsia-mem", - "//zircon/system/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c", ] } } else if (crashpad_is_in_chromium) { @@ -28,7 +27,6 @@ if (crashpad_is_in_fuchsia) { public_deps = [ "//third_party/fuchsia-sdk/sdk:fdio", "//third_party/fuchsia-sdk/sdk:mem", - "//third_party/fuchsia-sdk/sdk:sysinfo", "//third_party/fuchsia-sdk/sdk:zx", ] } @@ -115,11 +113,6 @@ if (crashpad_is_in_fuchsia) { header_stem = "fuchsia/mem" library_name = "fuchsia.mem" }, - { - fidl = "$sdk_fidl_sources_path/fuchsia.sysinfo/sysinfo.fidl" - header_stem = "fuchsia/sysinfo" - library_name = "fuchsia.sysinfo" - }, ] foreach(fidl_source, fidl_sources) { @@ -245,7 +238,6 @@ if (crashpad_is_in_fuchsia) { ":fidl_base", ":fidl_cpp_base", ":fuchsia.mem_cpp", - ":fuchsia.sysinfo_c", ":zx", ] diff --git a/util/fuchsia/koid_utilities.cc b/util/fuchsia/koid_utilities.cc index 09c7e541..f0377dc3 100644 --- a/util/fuchsia/koid_utilities.cc +++ b/util/fuchsia/koid_utilities.cc @@ -14,7 +14,6 @@ #include "util/fuchsia/koid_utilities.h" -#include <fuchsia/sysinfo/c/fidl.h> #include <lib/fdio/fdio.h> #include <lib/zx/channel.h> #include <lib/zx/job.h> From a519f1bec3d8d675c05304b18339da5bfa42236e Mon Sep 17 00:00:00 2001 From: Scott Graham <scottmg@chromium.org> Date: Fri, 24 Apr 2020 14:50:53 -0700 Subject: [PATCH 394/401] fuchsia: Update build to use new "GN" SDK This reworks the SDK pull to get the new packaging of the SDK. Includes DEPS update to roll mini_chromium with two changes: f7bd221 fuchsia: Remove fuchsia_sdk declare_args, add copy() tool 8ca5ea3 fuchsia: Use sdk/$host_os-amd64 for sdk path Bug: fuchsia:7802 Change-Id: Ifcb0e90b19c7eddc32a37422e6951f214dcdfd36 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2165494 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Scott Graham <scottmg@chromium.org> --- DEPS | 6 +- third_party/fuchsia/BUILD.gn | 224 ++--------------------------------- 2 files changed, 11 insertions(+), 219 deletions(-) diff --git a/DEPS b/DEPS index 0c5da0a6..0065e3c5 100644 --- a/DEPS +++ b/DEPS @@ -42,7 +42,7 @@ deps = { '7bde79cc274d06451bf65ae82c012a5d3e476b5a', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '641fcf9bbc1277e8153ac7e86d5b8f9340b1bfdd', + '8ca5ea356cdb97913d62d379d503567a80d90726', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020', @@ -104,7 +104,7 @@ deps = { 'crashpad/third_party/fuchsia/sdk/mac-amd64': { 'packages': [ { - 'package': 'fuchsia/sdk/core/mac-amd64', + 'package': 'fuchsia/sdk/gn/mac-amd64', 'version': 'latest' }, ], @@ -114,7 +114,7 @@ deps = { 'crashpad/third_party/fuchsia/sdk/linux-amd64': { 'packages': [ { - 'package': 'fuchsia/sdk/core/linux-amd64', + 'package': 'fuchsia/sdk/gn/linux-amd64', 'version': 'latest' }, ], diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 1fa174aa..7c1efd92 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -25,225 +25,17 @@ if (crashpad_is_in_fuchsia) { } else if (crashpad_is_in_chromium) { group("fuchsia") { public_deps = [ - "//third_party/fuchsia-sdk/sdk:fdio", - "//third_party/fuchsia-sdk/sdk:mem", - "//third_party/fuchsia-sdk/sdk:zx", + "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mem", + "//third_party/fuchsia-sdk/sdk/pkg/fdio", + "//third_party/fuchsia-sdk/sdk/pkg/zx", ] } } else { - sdk_path = "sdk/$host_os-amd64" - sdk_pkg_path = "$sdk_path/pkg" - sdk_fidl_sources_path = "$sdk_path/fidl" - - config("zx_config") { - include_dirs = [ "$sdk_pkg_path/zx/include" ] - } - - fidl_root_gen_dir = "$root_gen_dir/fidl/include" - config("fidl_config") { - include_dirs = [ - fidl_root_gen_dir, - "$sdk_pkg_path/fidl/include", - "$sdk_pkg_path/fidl_base/include", - "$sdk_pkg_path/async/include", - "$sdk_pkg_path/fidl_cpp/include", - "$sdk_pkg_path/fidl_cpp_base/include", - "$sdk_pkg_path/fidl_cpp_sync/include", - "$sdk_pkg_path/fit/include", - ] - } - - source_set("zx") { - sources = [ - "$sdk_pkg_path/zx/channel.cc", - "$sdk_pkg_path/zx/event.cc", - "$sdk_pkg_path/zx/eventpair.cc", - "$sdk_pkg_path/zx/fifo.cc", - "$sdk_pkg_path/zx/guest.cc", - "$sdk_pkg_path/zx/interrupt.cc", - "$sdk_pkg_path/zx/job.cc", - "$sdk_pkg_path/zx/port.cc", - "$sdk_pkg_path/zx/process.cc", - "$sdk_pkg_path/zx/resource.cc", - "$sdk_pkg_path/zx/socket.cc", - "$sdk_pkg_path/zx/thread.cc", - "$sdk_pkg_path/zx/timer.cc", - "$sdk_pkg_path/zx/vmar.cc", - "$sdk_pkg_path/zx/vmo.cc", - ] - - public_configs = [ ":zx_config" ] - } - - source_set("fidl_base") { - sources = [ - "$sdk_pkg_path/fidl_base/builder.cc", - "$sdk_pkg_path/fidl_base/decoding.cc", - "$sdk_pkg_path/fidl_base/encoding.cc", - "$sdk_pkg_path/fidl_base/formatting.cc", - "$sdk_pkg_path/fidl_base/linearizing.cc", - "$sdk_pkg_path/fidl_base/message.cc", - "$sdk_pkg_path/fidl_base/message_buffer.cc", - "$sdk_pkg_path/fidl_base/message_builder.cc", - "$sdk_pkg_path/fidl_base/transformer.cc", - "$sdk_pkg_path/fidl_base/txn_header.c", - "$sdk_pkg_path/fidl_base/validating.cc", - "$sdk_pkg_path/fidl_base/walker.cc", - ] - - public_configs = [ ":fidl_config" ] - } - - source_set("fidl_cpp_base") { - sources = [ - "$sdk_pkg_path/fidl_cpp_base/clone.cc", - "$sdk_pkg_path/fidl_cpp_base/decoder.cc", - "$sdk_pkg_path/fidl_cpp_base/encoder.cc", - ] - - public_configs = [ - ":fidl_config", - ":zx_config", - ] - } - - fidl_sources = [ - { - fidl = "$sdk_fidl_sources_path/fuchsia.mem/buffer.fidl" - header_stem = "fuchsia/mem" - library_name = "fuchsia.mem" - }, - ] - - foreach(fidl_source, fidl_sources) { - fidl_stem = "$target_gen_dir/fidl/${fidl_source.library_name}" - json_representation = "$fidl_stem/intermediary_representation.json" - c_stem = "$fidl_root_gen_dir/${fidl_source.header_stem}/c" - c_header = "$c_stem/fidl.h" - c_client = "$c_stem/client.cc" - cpp_stem = "$fidl_root_gen_dir/${fidl_source.header_stem}/cpp/fidl" - cpp_header = "$cpp_stem.h" - cpp_source = "$cpp_stem.cc" - coding_tables = "$fidl_stem/tables.c" - - # Compiles the .fidl file, outputs the intermediary JSON representation - # and generates the C bindings. - action("fidlc_${fidl_source.library_name}") { - visibility = [ ":*" ] - - script = "runner.py" - - args = [ - rebase_path("$sdk_path/tools/fidlc", root_build_dir), - "--c-header", - rebase_path(c_header, root_build_dir), - "--c-client", - rebase_path(c_client, root_build_dir), - "--tables", - rebase_path(coding_tables, root_build_dir), - "--json", - rebase_path(json_representation, root_build_dir), - "--name", - fidl_source.library_name, - "--files", - rebase_path(fidl_source.fidl, root_build_dir), - ] - - inputs = [ - "$sdk_path/tools/fidlc", - fidl_source.fidl, - ] - - outputs = [ - c_client, - c_header, - coding_tables, - json_representation, - ] - } - - # Generates the C++ bindings from the intermediary JSON representation. - action("fidlgen_cpp_${fidl_source.library_name}") { - visibility = [ ":*" ] - - script = "runner.py" - - args = [ - rebase_path("$sdk_path/tools/fidlgen", root_build_dir), - "--json", - rebase_path(json_representation, root_build_dir), - "--include-base", - rebase_path(fidl_root_gen_dir, root_build_dir), - "--output-base", - rebase_path(cpp_stem, root_build_dir), - "--generators", - "cpp", - ] - - inputs = [ - "$sdk_path/tools/fidlgen", - json_representation, - ] - - outputs = [ - cpp_header, - cpp_source, - ] - - deps = [ ":fidlc_${fidl_source.library_name}" ] - } - - source_set("${fidl_source.library_name}_tables") { - sources = [ coding_tables ] - - deps = [ ":fidlc_${fidl_source.library_name}" ] - - public_configs = [ ":fidl_config" ] - } - - source_set("${fidl_source.library_name}_c") { - sources = [ - c_client, - c_header, - ] - - deps = [ - ":${fidl_source.library_name}_tables", - ":fidlc_${fidl_source.library_name}", - ] - - public_configs = [ ":fidl_config" ] - } - - source_set("${fidl_source.library_name}_cpp") { - sources = [ - cpp_header, - cpp_source, - ] - - deps = [ - ":${fidl_source.library_name}_tables", - ":fidlgen_cpp_${fidl_source.library_name}", - ] - - public_configs = [ - ":fidl_config", - ":zx_config", - ] - } - } - - static_library("fuchsia") { - deps = [ - ":fidl_base", - ":fidl_cpp_base", - ":fuchsia.mem_cpp", - ":zx", - ] - - public_configs = [ - ":fidl_config", - ":zx_config", + group("fuchsia") { + public_deps = [ + "//third_party/fuchsia/sdk/$host_os-amd64/fidl/fuchsia.mem", + "//third_party/fuchsia/sdk/$host_os-amd64/pkg/fdio", + "//third_party/fuchsia/sdk/$host_os-amd64/pkg/zx", ] } } From 6d8b196150da4bca59c5a9c3a8a20f33467ea3c2 Mon Sep 17 00:00:00 2001 From: Francois Rousseau <frousseau@google.com> Date: Fri, 24 Apr 2020 14:32:54 -0700 Subject: [PATCH 395/401] [fuchsia] remove handler * Fuchsia only uses Crashpad for minidump generation, report database and report upload, not for the actual exception handling so it does not need a handler class * the current handler class didn't have tests anyway * Chromium on Fuchsia relies on the platform exception handling instead of rolling its own Crashpad exception handler * this avoids us having to maintain an exception handler in another repo * this removes the last FIDL dependency in Crashpad TESTED=`fx test crashpad_test` Change-Id: Ie3998f709e7cc4252dd551882a23b337864da85e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2165638 Commit-Queue: Francois Rousseau <frousseau@google.com> Reviewed-by: Scott Graham <scottmg@chromium.org> --- BUILD.gn | 10 +- client/BUILD.gn | 2 +- handler/BUILD.gn | 13 -- .../fuchsia/crash_report_exception_handler.cc | 151 ------------------ .../fuchsia/crash_report_exception_handler.h | 100 ------------ handler/fuchsia/exception_handler_server.cc | 89 ----------- handler/fuchsia/exception_handler_server.h | 56 ------- handler/handler_main.cc | 49 ------ third_party/fuchsia/BUILD.gn | 3 - 9 files changed, 6 insertions(+), 467 deletions(-) delete mode 100644 handler/fuchsia/crash_report_exception_handler.cc delete mode 100644 handler/fuchsia/crash_report_exception_handler.h delete mode 100644 handler/fuchsia/exception_handler_server.cc delete mode 100644 handler/fuchsia/exception_handler_server.h diff --git a/BUILD.gn b/BUILD.gn index 381271a8..98218af1 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -42,10 +42,10 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "test:test_test", ] if (!crashpad_is_ios) { - deps += [ - "handler:handler_test", - "snapshot:snapshot_test", - ] + deps += [ "snapshot:snapshot_test" ] + } + if (!crashpad_is_ios && !crashpad_is_fuchsia) { + deps += [ "handler:handler_test" ] } if (crashpad_is_in_fuchsia) { # TODO(fuchsia:46559): Fix the leaks and remove this. @@ -182,7 +182,7 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { "handler:handler_test", "test:gtest_main", ] - if (crashpad_is_ios) { + if (crashpad_is_ios || crashpad_is_fuchsia) { deps -= [ "handler:handler_test" ] } } diff --git a/client/BUILD.gn b/client/BUILD.gn index 11ba757b..b748c3fe 100644 --- a/client/BUILD.gn +++ b/client/BUILD.gn @@ -163,7 +163,7 @@ source_set("client_test") { "../util", ] - if (!crashpad_is_ios) { + if (!crashpad_is_ios && !crashpad_is_fuchsia) { data_deps = [ "../handler:crashpad_handler" ] } diff --git a/handler/BUILD.gn b/handler/BUILD.gn index 2f608cb1..17c4cbd6 100644 --- a/handler/BUILD.gn +++ b/handler/BUILD.gn @@ -65,15 +65,6 @@ static_library("handler") { ] } - if (crashpad_is_fuchsia) { - sources += [ - "fuchsia/crash_report_exception_handler.cc", - "fuchsia/crash_report_exception_handler.h", - "fuchsia/exception_handler_server.cc", - "fuchsia/exception_handler_server.h", - ] - } - public_configs = [ "..:crashpad_config" ] public_deps = [ @@ -91,10 +82,6 @@ static_library("handler") { if (crashpad_is_win) { cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union } - - if (crashpad_is_fuchsia) { - deps += [ "../third_party/fuchsia" ] - } } if (crashpad_is_android) { diff --git a/handler/fuchsia/crash_report_exception_handler.cc b/handler/fuchsia/crash_report_exception_handler.cc deleted file mode 100644 index ad846d29..00000000 --- a/handler/fuchsia/crash_report_exception_handler.cc +++ /dev/null @@ -1,151 +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 "handler/fuchsia/crash_report_exception_handler.h" - -#include <lib/zx/thread.h> -#include <zircon/errors.h> -#include <zircon/status.h> -#include <zircon/syscalls/exception.h> - -#include "base/fuchsia/fuchsia_logging.h" -#include "client/settings.h" -#include "minidump/minidump_file_writer.h" -#include "minidump/minidump_user_extension_stream_data_source.h" -#include "snapshot/fuchsia/process_snapshot_fuchsia.h" -#include "util/fuchsia/koid_utilities.h" -#include "util/fuchsia/scoped_task_suspend.h" - -namespace crashpad { - -CrashReportExceptionHandler::CrashReportExceptionHandler( - CrashReportDatabase* database, - CrashReportUploadThread* upload_thread, - const std::map<std::string, std::string>* process_annotations, - const std::map<std::string, fuchsia::mem::Buffer>* 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() {} - -bool CrashReportExceptionHandler::HandleException(const zx::process& process, - const zx::thread& thread, - UUID* local_report_id) { - ScopedTaskSuspend suspend(process); - - ProcessSnapshotFuchsia process_snapshot; - if (!process_snapshot.Initialize(process)) { - return false; - } - - CrashpadInfoClientOptions client_options; - process_snapshot.GetCrashpadOptions(&client_options); - - if (client_options.crashpad_handler_behavior == TriState::kDisabled) { - return true; - } - - zx_exception_report_t report; - zx_status_t status = thread.get_info(ZX_INFO_THREAD_EXCEPTION_REPORT, - &report, - sizeof(report), - nullptr, - nullptr); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) - << "zx_object_get_info ZX_INFO_THREAD_EXCEPTION_REPORT"; - return false; - } - - zx_koid_t thread_id = GetKoidForHandle(thread); - if (!process_snapshot.InitializeException(thread_id, report)) { - return false; - } - - UUID client_id; - Settings* const settings = database_->GetSettings(); - if (settings) { - // If GetSettings() or GetClientID() fails, something else will log a - // message and client_id will be left at its default value, all zeroes, - // which is appropriate. - settings->GetClientID(&client_id); - } - - process_snapshot.SetClientID(client_id); - process_snapshot.SetAnnotationsSimpleMap(*process_annotations_); - - std::unique_ptr<CrashReportDatabase::NewReport> new_report; - CrashReportDatabase::OperationStatus database_status = - database_->PrepareNewCrashReport(&new_report); - if (database_status != CrashReportDatabase::kNoError) { - return false; - } - - process_snapshot.SetReportID(new_report->ReportID()); - - MinidumpFileWriter minidump; - minidump.InitializeFromSnapshot(&process_snapshot); - AddUserExtensionStreams( - user_stream_data_sources_, &process_snapshot, &minidump); - - if (!minidump.WriteEverything(new_report->Writer())) { - 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 VMO 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_) { - // TODO(frousseau): make FileWriter VMO-aware. - FileWriter* writer = new_report->AddAttachment(it.first); - if (!writer) { - continue; - } - auto data = std::make_unique<uint8_t[]>(it.second.size); - const zx_status_t read_status = - it.second.vmo.read(data.get(), 0u, it.second.size); - if (read_status != ZX_OK) { - ZX_LOG(ERROR, read_status) - << "could not read VMO for attachment " << it.first; - // Not being able to read the VMO isn't considered fatal, and - // should not prevent the report from being processed. - continue; - } - writer->Write(data.get(), it.second.size); - } - } - - UUID uuid; - database_status = - database_->FinishedWritingCrashReport(std::move(new_report), &uuid); - if (database_status != CrashReportDatabase::kNoError) { - return false; - } - if (local_report_id != nullptr) { - *local_report_id = uuid; - } - - if (upload_thread_) { - upload_thread_->ReportPending(uuid); - } - - return true; -} - -} // namespace crashpad diff --git a/handler/fuchsia/crash_report_exception_handler.h b/handler/fuchsia/crash_report_exception_handler.h deleted file mode 100644 index 06c432f7..00000000 --- a/handler/fuchsia/crash_report_exception_handler.h +++ /dev/null @@ -1,100 +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. - -#ifndef CRASHPAD_HANDLER_FUCHSIA_CRASH_REPORT_EXCEPTION_HANDLER_H_ -#define CRASHPAD_HANDLER_FUCHSIA_CRASH_REPORT_EXCEPTION_HANDLER_H_ - -#include <fuchsia/mem/cpp/fidl.h> -#include <lib/zx/port.h> -#include <lib/zx/process.h> -#include <lib/zx/thread.h> -#include <stdint.h> -#include <zircon/types.h> - -#include <map> -#include <string> - -#include "base/files/file_path.h" -#include "base/macros.h" -#include "client/crash_report_database.h" -#include "handler/crash_report_upload_thread.h" -#include "handler/user_stream_data_source.h" -#include "util/misc/uuid.h" - -namespace crashpad { - -//! \brief An exception handler that writes crash reports for exception messages -//! to a CrashReportDatabase. -class CrashReportExceptionHandler { - public: - //! \brief Creates a new object that will store crash reports in \a database. - //! - //! \param[in] database The database to store crash reports in. Weak. - //! \param[in] upload_thread The upload thread to notify when a new crash - //! report is written into \a database. - //! \param[in] process_annotations A map of annotations to insert as - //! process-level annotations into each crash report that is written. Do - //! not confuse this with module-level annotations, which are under the - //! control of the crashing process, and are used to implement Chrome's - //! "crash keys." Process-level annotations are those that are beyond the - //! control of the crashing process, which must reliably be set even if - //! the process crashes before it’s able to establish its own annotations. - //! 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 keys to VMOs to be included in the - //! report. Each time a report is written, the VMOs will be read in their - //! entirety and included in the report using the 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 - //! minidump streams. `nullptr` if not required. - CrashReportExceptionHandler( - CrashReportDatabase* database, - CrashReportUploadThread* upload_thread, - const std::map<std::string, std::string>* process_annotations, - const std::map<std::string, fuchsia::mem::Buffer>* process_attachments, - const UserStreamDataSources* user_stream_data_sources); - - ~CrashReportExceptionHandler(); - - //! \brief Called when the exception handler server has caught an exception - //! and wants a crash dump to be taken. - //! - //! \param[in] process The handle to the process which sustained the - //! exception. - //! \param[in] thread The handle to the thread of \a process which sustained - //! the exception. - //! \param[out] local_report_id The unique identifier for the report created - //! in the local report database. Optional. - //! \return `true` on success, or `false` with an error logged. - bool HandleException(const zx::process& process, - const zx::thread& thread, - UUID* local_report_id = nullptr); - - private: - CrashReportDatabase* database_; // weak - CrashReportUploadThread* upload_thread_; // weak - const std::map<std::string, std::string>* process_annotations_; // weak - const std::map<std::string, fuchsia::mem::Buffer>* - process_attachments_; // weak - const UserStreamDataSources* user_stream_data_sources_; // weak - - DISALLOW_COPY_AND_ASSIGN(CrashReportExceptionHandler); -}; - -} // namespace crashpad - -#endif // CRASHPAD_HANDLER_FUCHSIA_CRASH_REPORT_EXCEPTION_HANDLER_H_ diff --git a/handler/fuchsia/exception_handler_server.cc b/handler/fuchsia/exception_handler_server.cc deleted file mode 100644 index e468fe3b..00000000 --- a/handler/fuchsia/exception_handler_server.cc +++ /dev/null @@ -1,89 +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 "handler/fuchsia/exception_handler_server.h" - -#include <lib/zx/exception.h> -#include <lib/zx/time.h> -#include <zircon/syscalls/exception.h> - -#include <utility> - -#include "base/fuchsia/fuchsia_logging.h" -#include "base/logging.h" -#include "handler/fuchsia/crash_report_exception_handler.h" - -namespace crashpad { - -ExceptionHandlerServer::ExceptionHandlerServer(zx::job root_job, - zx::channel exception_channel) - : root_job_(std::move(root_job)), - exception_channel_(std::move(exception_channel)) {} - -ExceptionHandlerServer::~ExceptionHandlerServer() = default; - -void ExceptionHandlerServer::Run(CrashReportExceptionHandler* handler) { - while (true) { - zx_signals_t signals; - zx_status_t status = exception_channel_.wait_one( - ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, - zx::time::infinite(), - &signals); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_port_wait, aborting"; - return; - } - - if (signals & ZX_CHANNEL_READABLE) { - zx_exception_info_t info; - zx::exception exception; - status = exception_channel_.read(0, - &info, - exception.reset_and_get_address(), - sizeof(info), - 1, - nullptr, - nullptr); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_channel_read, aborting"; - return; - } - - zx::process process; - status = exception.get_process(&process); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_exception_get_process, aborting"; - return; - } - - zx::thread thread; - status = exception.get_thread(&thread); - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "zx_exception_get_thread, aborting"; - return; - } - - bool result = - handler->HandleException(std::move(process), std::move(thread)); - if (!result) { - LOG(ERROR) << "HandleException failed"; - } - } else { - // Job terminated, exit the loop. - return; - } - } -} - -} // namespace crashpad diff --git a/handler/fuchsia/exception_handler_server.h b/handler/fuchsia/exception_handler_server.h deleted file mode 100644 index 85a7b7bd..00000000 --- a/handler/fuchsia/exception_handler_server.h +++ /dev/null @@ -1,56 +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. - -#ifndef CRASHPAD_HANDLER_FUCHSIA_EXCEPTION_HANDLER_SERVER_H_ -#define CRASHPAD_HANDLER_FUCHSIA_EXCEPTION_HANDLER_SERVER_H_ - -#include <lib/zx/channel.h> -#include <lib/zx/job.h> - -#include "base/macros.h" - -namespace crashpad { - -class CrashReportExceptionHandler; - -//! \brief Runs the main exception-handling server in Crashpad's handler -//! process. -class ExceptionHandlerServer { - public: - //! \brief Constructs an ExceptionHandlerServer object. - //! - //! \param[in] root_job The root of the tree of processes that will be handled - //! by this server. It is assumed that \a exception_channel is the - // exception channel of this job. - //! \param[in] exception_channel The exception channel that this server will - //! monitor. - ExceptionHandlerServer(zx::job root_job, zx::channel exception_channel); - ~ExceptionHandlerServer(); - - //! \brief Runs the exception-handling server. - //! - //! \param[in] handler The handler to which the exceptions are delegated when - //! they are caught in Run(). Ownership is not transferred. - void Run(CrashReportExceptionHandler* handler); - - private: - zx::job root_job_; - zx::channel exception_channel_; - - DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServer); -}; - -} // namespace crashpad - -#endif // CRASHPAD_HANDLER_FUCHSIA_EXCEPTION_HANDLER_SERVER_H_ diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 69da0f61..d56857ff 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -86,15 +86,6 @@ #include "util/win/handle.h" #include "util/win/initial_client_data.h" #include "util/win/session_end_watcher.h" -#elif defined(OS_FUCHSIA) -#include <zircon/process.h> -#include <zircon/processargs.h> - -#include <lib/zx/channel.h> -#include <lib/zx/job.h> - -#include "handler/fuchsia/crash_report_exception_handler.h" -#include "handler/fuchsia/exception_handler_server.h" #elif defined(OS_LINUX) #include "handler/linux/crash_report_exception_handler.h" #include "handler/linux/exception_handler_server.h" @@ -420,22 +411,6 @@ void InstallCrashHandler() { ALLOW_UNUSED_LOCAL(terminate_handler); } -#elif defined(OS_FUCHSIA) - -void InstallCrashHandler() { - // There's nothing to do here. Crashes in this process will already be caught - // here because this handler process is in the same job that has had its - // exception port bound. - - // TODO(scottmg): This should collect metrics on handler crashes, at a - // minimum. https://crashpad.chromium.org/bug/230. -} - -void ReinstallCrashHandler() { - // TODO(scottmg): Fuchsia: https://crashpad.chromium.org/bug/196 - NOTREACHED(); -} - #endif // OS_MACOSX void MonitorSelf(const Options& options) { @@ -1013,10 +988,6 @@ int HandlerMain(int argc, database.get(), static_cast<CrashReportUploadThread*>(upload_thread.Get()), &options.annotations, -#if defined(OS_FUCHSIA) - // TODO(scottmg): Process level file attachments, and for all platforms. - nullptr, -#endif #if defined(OS_ANDROID) options.write_minidump_to_database, options.write_minidump_to_log, @@ -1100,26 +1071,6 @@ int HandlerMain(int argc, if (!options.pipe_name.empty()) { exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name)); } -#elif defined(OS_FUCHSIA) - // These handles are logically "moved" into these variables when retrieved by - // zx_take_startup_handle(). Both are given to ExceptionHandlerServer which - // owns them in this process. There is currently no "connect-later" mode on - // Fuchsia, all the binding must be done by the client before starting - // crashpad_handler. - zx::job root_job(zx_take_startup_handle(PA_HND(PA_USER0, 0))); - if (!root_job.is_valid()) { - LOG(ERROR) << "no job handle passed in startup handle 0"; - return EXIT_FAILURE; - } - - zx::channel exception_channel(zx_take_startup_handle(PA_HND(PA_USER0, 1))); - if (!exception_channel.is_valid()) { - LOG(ERROR) << "no exception channel handle passed in startup handle 1"; - return EXIT_FAILURE; - } - - ExceptionHandlerServer exception_handler_server(std::move(root_job), - std::move(exception_channel)); #elif defined(OS_LINUX) || defined(OS_ANDROID) ExceptionHandlerServer exception_handler_server; #endif // OS_MACOSX diff --git a/third_party/fuchsia/BUILD.gn b/third_party/fuchsia/BUILD.gn index 7c1efd92..7e06289c 100644 --- a/third_party/fuchsia/BUILD.gn +++ b/third_party/fuchsia/BUILD.gn @@ -19,13 +19,11 @@ if (crashpad_is_in_fuchsia) { public_deps = [ "//zircon/public/lib/fdio", "//zircon/public/lib/zx", - "//zircon/system/fidl/fuchsia-mem", ] } } else if (crashpad_is_in_chromium) { group("fuchsia") { public_deps = [ - "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mem", "//third_party/fuchsia-sdk/sdk/pkg/fdio", "//third_party/fuchsia-sdk/sdk/pkg/zx", ] @@ -33,7 +31,6 @@ if (crashpad_is_in_fuchsia) { } else { group("fuchsia") { public_deps = [ - "//third_party/fuchsia/sdk/$host_os-amd64/fidl/fuchsia.mem", "//third_party/fuchsia/sdk/$host_os-amd64/pkg/fdio", "//third_party/fuchsia/sdk/$host_os-amd64/pkg/zx", ] From 17a515d33dc56b9d6a3c982d2d2e81c61ff9ba41 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Sat, 25 Apr 2020 17:16:10 -0400 Subject: [PATCH 396/401] [ios] Bring up first draft Mach exception server. Add Mach exception server and fill out exceptions snapshot. Note that: - The 'capture' portion of this CL will be moved out of the snapshot interface and into a separate in-process dump to disk location. - All of the pointer dereferences need to be wrapped in vm_read. - The read-fast-and-dump logic in exception_snapshot will end up in a different file completely, but until we pick a serialization/deserialization method, keep it as-is. Bug: crashpad:31 Change-Id: I44203aa44036a341d6b4517fde7ab0cb9d7e94d7 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2160122 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- client/crashpad_client.h | 9 +- client/crashpad_client_ios.cc | 206 ++++++++++++++---- client/crashpad_client_ios_test.mm | 17 +- snapshot/ios/exception_snapshot_ios.cc | 170 +++++++++++++-- snapshot/ios/exception_snapshot_ios.h | 21 +- snapshot/ios/process_snapshot_ios.cc | 33 ++- snapshot/ios/process_snapshot_ios.h | 15 +- snapshot/ios/thread_snapshot_ios.cc | 7 +- snapshot/ios/thread_snapshot_ios.h | 2 +- snapshot/mac/cpu_context_mac.cc | 112 +++++++++- snapshot/mac/cpu_context_mac.h | 29 ++- snapshot/mac/exception_snapshot_mac.cc | 9 +- test/ios/host/cptest_crash_view_controller.mm | 2 - util/BUILD.gn | 2 +- util/misc/capture_context.h | 10 +- 15 files changed, 558 insertions(+), 86 deletions(-) diff --git a/client/crashpad_client.h b/client/crashpad_client.h index 7a6a18a9..f5e02c9c 100644 --- a/client/crashpad_client.h +++ b/client/crashpad_client.h @@ -431,18 +431,19 @@ class CrashpadClient { //! //! This method is only defined on iOS. //! - //! \return `true` on success, `false` on failure with a message logged. - //! //! TODO(justincohen): This method will need to take database, metrics_dir, //! url and annotations eventually. - bool StartCrashpadInProcessHandler(); + void StartCrashpadInProcessHandler(); // TODO(justincohen): This method is purely for bringing up iOS interfaces. //! \brief Requests that the handler capture a dump even though there hasn't //! been a crash. //! //! A handler must have already been installed before calling this method. - static void DumpWithoutCrash(); + //! + //! \param[in] context A NativeCPUContext, generally captured by + //! CaptureContext() or similar. + static void DumpWithoutCrash(NativeCPUContext* context); #endif #if defined(OS_MACOSX) || DOXYGEN diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc index 465867af..342e1090 100644 --- a/client/crashpad_client_ios.cc +++ b/client/crashpad_client_ios.cc @@ -16,65 +16,192 @@ #include <unistd.h> +#include <ios> + #include "base/logging.h" -#include "base/strings/stringprintf.h" -#include "client/client_argv_handling.h" +#include "base/mac/mach_logging.h" +#include "base/mac/scoped_mach_port.h" +#include "base/stl_util.h" #include "snapshot/ios/process_snapshot_ios.h" #include "util/ios/exception_processor.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" +#include "util/mach/mach_message.h" +#include "util/mach/mach_message_server.h" +#include "util/misc/initialization_state_dcheck.h" #include "util/posix/signals.h" +#include "util/thread/thread.h" namespace crashpad { namespace { -// A base class for Crashpad signal handler implementations. -class SignalHandler { +// A base class for signal handler and Mach exception server. +class CrashHandler : public Thread, public UniversalMachExcServer::Interface { public: - // Returns the currently installed signal hander. - static SignalHandler* Get() { - static SignalHandler* instance = new SignalHandler(); + static CrashHandler* Get() { + static CrashHandler* instance = new CrashHandler(); return instance; } - bool Install(const std::set<int>* unhandled_signals) { - return Signals::InstallCrashHandlers( - HandleSignal, 0, &old_actions_, unhandled_signals); + void Initialize() { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + InstallMachExceptionHandler(); + CHECK(Signals::InstallHandler(SIGABRT, CatchSignal, 0, &old_action_)); + INITIALIZATION_STATE_SET_VALID(initialized_); } - void HandleCrash(int signo, siginfo_t* siginfo, void* context) { - // TODO(justincohen): This is incomplete. - ProcessSnapshotIOS process_snapshot; - process_snapshot.Initialize(system_data); - process_snapshot.SetException(siginfo, - reinterpret_cast<ucontext_t*>(context)); + void DumpWithoutCrash(NativeCPUContext* context) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + mach_exception_data_type_t code[2] = {}; + static constexpr int kSimulatedException = -1; + HandleMachException(MACH_EXCEPTION_CODES, + mach_thread_self(), + kSimulatedException, + code, + base::size(code), + MACHINE_THREAD_STATE, + reinterpret_cast<ConstThreadState>(context), + MACHINE_THREAD_STATE_COUNT); } private: - SignalHandler() = default; + CrashHandler() = default; - // The base implementation for all signal handlers, suitable for calling - // directly to simulate signal delivery. - void HandleCrashAndReraiseSignal(int signo, - siginfo_t* siginfo, - void* context) { - HandleCrash(signo, siginfo, context); - // Always call system handler. - Signals::RestoreHandlerAndReraiseSignalOnReturn( - siginfo, old_actions_.ActionForSignal(signo)); + void InstallMachExceptionHandler() { + exception_port_.reset(NewMachPort(MACH_PORT_RIGHT_RECEIVE)); + CHECK(exception_port_.is_valid()); + + kern_return_t kr = mach_port_insert_right(mach_task_self(), + exception_port_.get(), + exception_port_.get(), + MACH_MSG_TYPE_MAKE_SEND); + MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_insert_right"; + + // TODO: Use SwapExceptionPort instead and put back EXC_MASK_BREAKPOINT. + const exception_mask_t mask = + ExcMaskAll() & + ~(EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT | + EXC_MASK_RPC_ALERT | EXC_MASK_GUARD); + ExceptionPorts exception_ports(ExceptionPorts::kTargetTypeTask, TASK_NULL); + exception_ports.GetExceptionPorts(mask, &original_handlers_); + exception_ports.SetExceptionPort( + mask, + exception_port_.get(), + EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, + MACHINE_THREAD_STATE); + + Start(); + } + + // Thread: + + void ThreadMain() override { + UniversalMachExcServer universal_mach_exc_server(this); + while (true) { + mach_msg_return_t mr = + MachMessageServer::Run(&universal_mach_exc_server, + exception_port_.get(), + MACH_MSG_OPTION_NONE, + MachMessageServer::kPersistent, + MachMessageServer::kReceiveLargeIgnore, + kMachMessageTimeoutWaitIndefinitely); + MACH_CHECK(mr == MACH_SEND_INVALID_DEST, mr) << "MachMessageServer::Run"; + } + } + + // UniversalMachExcServer::Interface: + + kern_return_t CatchMachException(exception_behavior_t behavior, + exception_handler_t exception_port, + thread_t thread, + task_t task, + exception_type_t exception, + const mach_exception_data_type_t* code, + mach_msg_type_number_t code_count, + thread_state_flavor_t* flavor, + ConstThreadState old_state, + mach_msg_type_number_t old_state_count, + thread_state_t new_state, + mach_msg_type_number_t* new_state_count, + const mach_msg_trailer_t* trailer, + bool* destroy_complex_request) override { + *destroy_complex_request = true; + + // TODO(justincohen): Forward exceptions to original_handlers_ with + // UniversalExceptionRaise. + + // iOS shouldn't have any child processes, but just in case, those will + // 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(); + return KERN_FAILURE; + } + + HandleMachException(behavior, + thread, + exception, + code, + code_count, + *flavor, + old_state, + old_state_count); + + // Respond with KERN_FAILURE so the system will continue to handle this + // exception as a crash. + return KERN_FAILURE; + } + + void HandleMachException(exception_behavior_t behavior, + thread_t thread, + exception_type_t exception, + const mach_exception_data_type_t* code, + mach_msg_type_number_t code_count, + thread_state_flavor_t flavor, + ConstThreadState old_state, + mach_msg_type_number_t old_state_count) { + // TODO(justincohen): This is incomplete. + ProcessSnapshotIOS process_snapshot; + process_snapshot.Initialize(system_data_); + process_snapshot.SetExceptionFromMachException(behavior, + thread, + exception, + code, + code_count, + flavor, + old_state, + old_state_count); } // The signal handler installed at OS-level. - static void HandleSignal(int signo, siginfo_t* siginfo, void* context) { - Get()->HandleCrashAndReraiseSignal(signo, siginfo, context); + static void CatchSignal(int signo, siginfo_t* siginfo, void* context) { + Get()->HandleAndReraiseSignal( + signo, siginfo, reinterpret_cast<ucontext_t*>(context)); } - Signals::OldActions old_actions_ = {}; + void HandleAndReraiseSignal(int signo, + siginfo_t* siginfo, + ucontext_t* context) { + // TODO(justincohen): This is incomplete. + ProcessSnapshotIOS process_snapshot; + process_snapshot.Initialize(system_data_); + process_snapshot.SetExceptionFromSignal(siginfo, context); - // Collect some system data before the signal handler is triggered. - IOSSystemDataCollector system_data; + // Always call system handler. + Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, &old_action_); + } - DISALLOW_COPY_AND_ASSIGN(SignalHandler); + base::mac::ScopedMachReceiveRight exception_port_; + ExceptionPorts::ExceptionHandlerVector original_handlers_; + struct sigaction old_action_ = {}; + IOSSystemDataCollector system_data_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(CrashHandler); }; } // namespace @@ -83,16 +210,19 @@ CrashpadClient::CrashpadClient() {} CrashpadClient::~CrashpadClient() {} -bool CrashpadClient::StartCrashpadInProcessHandler() { +void CrashpadClient::StartCrashpadInProcessHandler() { InstallObjcExceptionPreprocessor(); - return SignalHandler::Get()->Install(nullptr); + + CrashHandler* crash_handler = CrashHandler::Get(); + DCHECK(crash_handler); + crash_handler->Initialize(); } // static -void CrashpadClient::DumpWithoutCrash() { - DCHECK(SignalHandler::Get()); - siginfo_t siginfo = {}; - SignalHandler::Get()->HandleCrash(siginfo.si_signo, &siginfo, nullptr); +void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) { + CrashHandler* crash_handler = CrashHandler::Get(); + DCHECK(crash_handler); + crash_handler->DumpWithoutCrash(context); } } // namespace crashpad diff --git a/client/crashpad_client_ios_test.mm b/client/crashpad_client_ios_test.mm index e07a1073..002fddbf 100644 --- a/client/crashpad_client_ios_test.mm +++ b/client/crashpad_client_ios_test.mm @@ -27,11 +27,24 @@ namespace { using CrashpadIOSClient = PlatformTest; -// TODO(justincohen): This is a placeholder. TEST_F(CrashpadIOSClient, DumpWithoutCrash) { CrashpadClient client; client.StartCrashpadInProcessHandler(); - client.DumpWithoutCrash(); + + NativeCPUContext context; +#if defined(ARCH_CPU_X86_64) + CaptureContext(&context); +#elif defined(ARCH_CPU_ARM64) + // TODO(justincohen): Implement CaptureContext for ARM64. + mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT; + kern_return_t kr = + thread_get_state(mach_thread_self(), + MACHINE_THREAD_STATE, + reinterpret_cast<thread_state_t>(&context), + &thread_state_count); + ASSERT_EQ(kr, KERN_SUCCESS); +#endif + client.DumpWithoutCrash(&context); } // This test is covered by a similar XCUITest, but for development purposes diff --git a/snapshot/ios/exception_snapshot_ios.cc b/snapshot/ios/exception_snapshot_ios.cc index 559b105e..db9e4891 100644 --- a/snapshot/ios/exception_snapshot_ios.cc +++ b/snapshot/ios/exception_snapshot_ios.cc @@ -22,6 +22,7 @@ #include "util/misc/from_pointer_cast.h" namespace crashpad { + namespace internal { ExceptionSnapshotIOS::ExceptionSnapshotIOS() @@ -30,24 +31,21 @@ ExceptionSnapshotIOS::ExceptionSnapshotIOS() codes_(), thread_id_(0), exception_address_(0), - signal_number_(0), - signal_code_(0), + exception_(0), + exception_info_(0), initialized_() {} ExceptionSnapshotIOS::~ExceptionSnapshotIOS() {} -bool ExceptionSnapshotIOS::Initialize(const siginfo_t* siginfo, - const ucontext_t* context) { +void ExceptionSnapshotIOS::InitializeFromSignal(const siginfo_t* siginfo, + const ucontext_t* context) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); - if (!context) - return false; - mcontext_t mcontext = context->uc_mcontext; #if defined(ARCH_CPU_X86_64) context_.architecture = kCPUArchitectureX86_64; context_.x86_64 = &context_x86_64_; - x86_debug_state64_t empty_debug_state; + x86_debug_state64_t empty_debug_state = {}; InitializeCPUContextX86_64(&context_x86_64_, THREAD_STATE_NONE, nullptr, @@ -58,7 +56,12 @@ bool ExceptionSnapshotIOS::Initialize(const siginfo_t* siginfo, #elif defined(ARCH_CPU_ARM64) context_.architecture = kCPUArchitectureARM64; context_.arm64 = &context_arm64_; - InitializeCPUContextARM64(&context_arm64_, &mcontext->__ss, &mcontext->__ns); + InitializeCPUContextARM64(&context_arm64_, + THREAD_STATE_NONE, + nullptr, + 0, + &mcontext->__ss, + &mcontext->__ns); #endif // Thread ID. @@ -75,12 +78,151 @@ bool ExceptionSnapshotIOS::Initialize(const siginfo_t* siginfo, thread_id_ = identifier_info.thread_id; } - signal_number_ = siginfo->si_signo; - signal_code_ = siginfo->si_code; + exception_ = siginfo->si_signo; + exception_info_ = siginfo->si_code; + + // TODO(justincohen): Investigate recording more codes_. + exception_address_ = FromPointerCast<uintptr_t>(siginfo->si_addr); + // TODO(justincohen): Record the source of the exception (signal, mach, etc). + + INITIALIZATION_STATE_SET_VALID(initialized_); +} + +void ExceptionSnapshotIOS::InitializeFromMachException( + exception_behavior_t behavior, + thread_t exception_thread, + exception_type_t exception, + const mach_exception_data_type_t* code, + mach_msg_type_number_t code_count, + thread_state_flavor_t flavor, + ConstThreadState state, + mach_msg_type_number_t state_count) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + codes_.push_back(exception); + // TODO: rationalize with the macOS implementation. + for (mach_msg_type_number_t code_index = 0; code_index < code_count; + ++code_index) { + codes_.push_back(code[code_index]); + } + exception_ = exception; + exception_info_ = code[0]; + + // For serialization, float_state and, on x86, debug_state, will be identical + // between here and the thread_snapshot version for thread_id. That means + // this block getting float_state and debug_state can be skipped when doing + // proper serialization. +#if defined(ARCH_CPU_X86_64) + x86_thread_state64_t thread_state; + x86_float_state64_t float_state; + x86_debug_state64_t debug_state; + mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT; + mach_msg_type_number_t float_state_count = x86_FLOAT_STATE64_COUNT; + mach_msg_type_number_t debug_state_count = x86_DEBUG_STATE64_COUNT; + const thread_state_flavor_t kThreadStateFlavor = x86_THREAD_STATE64; + const thread_state_flavor_t kFloatStateFlavor = x86_FLOAT_STATE64; + const thread_state_flavor_t kDebugStateFlavor = x86_DEBUG_STATE64; +#elif defined(ARCH_CPU_ARM64) + arm_thread_state64_t thread_state; + arm_neon_state64_t float_state; + mach_msg_type_number_t float_state_count = ARM_NEON_STATE64_COUNT; + mach_msg_type_number_t thread_state_count = ARM_THREAD_STATE64_COUNT; + const thread_state_flavor_t kThreadStateFlavor = ARM_THREAD_STATE64; + const thread_state_flavor_t kFloatStateFlavor = ARM_NEON_STATE64; +#endif + + kern_return_t kr = + thread_get_state(exception_thread, + kThreadStateFlavor, + reinterpret_cast<thread_state_t>(&thread_state), + &thread_state_count); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "thread_get_state(" << kThreadStateFlavor << ")"; + } + + kr = thread_get_state(exception_thread, + kFloatStateFlavor, + reinterpret_cast<thread_state_t>(&float_state), + &float_state_count); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "thread_get_state(" << kFloatStateFlavor << ")"; + } + +#if defined(ARCH_CPU_X86_64) + kr = thread_get_state(exception_thread, + kDebugStateFlavor, + reinterpret_cast<thread_state_t>(&debug_state), + &debug_state_count); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "thread_get_state(" << kDebugStateFlavor << ")"; + } +#endif + +#if defined(ARCH_CPU_X86_64) + context_.architecture = kCPUArchitectureX86_64; + context_.x86_64 = &context_x86_64_; + InitializeCPUContextX86_64(&context_x86_64_, + flavor, + state, + state_count, + &thread_state, + &float_state, + &debug_state); +#elif defined(ARCH_CPU_ARM64) + context_.architecture = kCPUArchitectureARM64; + context_.arm64 = &context_arm64_; + InitializeCPUContextARM64( + &context_arm64_, flavor, state, state_count, &thread_state, &float_state); +#endif + + // Thread ID. + thread_identifier_info identifier_info; + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + kr = thread_info(mach_thread_self(), + THREAD_IDENTIFIER_INFO, + reinterpret_cast<thread_info_t>(&identifier_info), + &count); + if (kr != KERN_SUCCESS) { + MACH_LOG(ERROR, kr) << "thread_identifier_info"; + } else { + thread_id_ = identifier_info.thread_id; + } + + // Normally, for EXC_BAD_ACCESS exceptions, the exception address is present + // in code[1]. It may or may not be the instruction pointer address (usually + // it’s not). code[1] may carry the exception address for other exception + // types too, but it’s not guaranteed. But for all other exception types, the + // instruction pointer will be the exception address, and in fact will be + // equal to codes[1] when it’s carrying the exception address. In those cases, + // just use the instruction pointer directly. + bool code_1_is_exception_address = exception_ == EXC_BAD_ACCESS; + +#if defined(ARCH_CPU_X86_64) + // For x86 and x86_64 EXC_BAD_ACCESS exceptions, some code[0] values + // indicate that code[1] does not (or may not) carry the exception address: + // EXC_I386_GPFLT (10.9.5 xnu-2422.115.4/osfmk/i386/trap.c user_trap() for + // T_GENERAL_PROTECTION) and the oddball (VM_PROT_READ | VM_PROT_EXECUTE) + // which collides with EXC_I386_BOUNDFLT (10.9.5 + // xnu-2422.115.4/osfmk/i386/fpu.c fpextovrflt()). Other EXC_BAD_ACCESS + // exceptions come through 10.9.5 xnu-2422.115.4/osfmk/i386/trap.c + // user_page_fault_continue() and do contain the exception address in + // code[1]. + if (exception_ == EXC_BAD_ACCESS && + (exception_info_ == EXC_I386_GPFLT || + exception_info_ == (VM_PROT_READ | VM_PROT_EXECUTE))) { + code_1_is_exception_address = false; + } +#endif + + if (code_1_is_exception_address) { + exception_address_ = code[1]; + } else { + exception_address_ = context_.InstructionPointer(); + } + INITIALIZATION_STATE_SET_VALID(initialized_); - return true; } const CPUContext* ExceptionSnapshotIOS::Context() const { @@ -95,12 +237,12 @@ uint64_t ExceptionSnapshotIOS::ThreadID() const { uint32_t ExceptionSnapshotIOS::Exception() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return signal_number_; + return exception_; } uint32_t ExceptionSnapshotIOS::ExceptionInfo() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - return signal_code_; + return exception_info_; } uint64_t ExceptionSnapshotIOS::ExceptionAddress() const { diff --git a/snapshot/ios/exception_snapshot_ios.h b/snapshot/ios/exception_snapshot_ios.h index 3c19a074..5c1337db 100644 --- a/snapshot/ios/exception_snapshot_ios.h +++ b/snapshot/ios/exception_snapshot_ios.h @@ -38,12 +38,25 @@ class ExceptionSnapshotIOS final : public ExceptionSnapshot { ExceptionSnapshotIOS(); ~ExceptionSnapshotIOS() override; - //! \brief Initializes the object. + //! \brief Initializes the object from a signal. //! //! \return `true` if the snapshot could be created, `false` otherwise with //! an appropriate message logged. - bool Initialize(const siginfo_t* siginfo, const ucontext_t* context); + void InitializeFromSignal(const siginfo_t* siginfo, + const ucontext_t* context); + //! \brief Initialize the object from a Mach exception for the current task. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! an appropriate message logged. + void InitializeFromMachException(exception_behavior_t behavior, + thread_t exception_thread, + exception_type_t exception, + const mach_exception_data_type_t* code, + mach_msg_type_number_t code_count, + thread_state_flavor_t flavor, + ConstThreadState state, + mach_msg_type_number_t state_count); // ExceptionSnapshot: const CPUContext* Context() const override; @@ -66,8 +79,8 @@ class ExceptionSnapshotIOS final : public ExceptionSnapshot { std::vector<uint64_t> codes_; uint64_t thread_id_; uintptr_t exception_address_; - int signal_number_; - int signal_code_; + uint32_t exception_; + uint32_t exception_info_; InitializationStateDcheck initialized_; DISALLOW_COPY_AND_ASSIGN(ExceptionSnapshotIOS); diff --git a/snapshot/ios/process_snapshot_ios.cc b/snapshot/ios/process_snapshot_ios.cc index 29701994..f45c6ee1 100644 --- a/snapshot/ios/process_snapshot_ios.cc +++ b/snapshot/ios/process_snapshot_ios.cc @@ -102,13 +102,36 @@ bool ProcessSnapshotIOS::Initialize(const IOSSystemDataCollector& system_data) { return true; } -void ProcessSnapshotIOS::SetException(const siginfo_t* siginfo, - const ucontext_t* context) { +void ProcessSnapshotIOS::SetExceptionFromSignal(const siginfo_t* siginfo, + const ucontext_t* context) { INITIALIZATION_STATE_DCHECK_VALID(initialized_); + DCHECK(!exception_.get()); + exception_.reset(new internal::ExceptionSnapshotIOS()); - if (!exception_->Initialize(siginfo, context)) { - exception_.reset(); - } + exception_->InitializeFromSignal(siginfo, context); +} + +void ProcessSnapshotIOS::SetExceptionFromMachException( + exception_behavior_t behavior, + thread_t exception_thread, + exception_type_t exception, + const mach_exception_data_type_t* code, + mach_msg_type_number_t code_count, + thread_state_flavor_t flavor, + ConstThreadState old_state, + mach_msg_type_number_t old_state_count) { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + DCHECK(!exception_.get()); + + exception_.reset(new internal::ExceptionSnapshotIOS()); + exception_->InitializeFromMachException(behavior, + exception_thread, + exception, + code, + code_count, + flavor, + old_state, + old_state_count); } pid_t ProcessSnapshotIOS::ProcessID() const { diff --git a/snapshot/ios/process_snapshot_ios.h b/snapshot/ios/process_snapshot_ios.h index 2332ff45..36b7ba13 100644 --- a/snapshot/ios/process_snapshot_ios.h +++ b/snapshot/ios/process_snapshot_ios.h @@ -44,7 +44,20 @@ class ProcessSnapshotIOS final : public ProcessSnapshot { //! an appropriate message logged. bool Initialize(const IOSSystemDataCollector& system_data); - void SetException(const siginfo_t* siginfo, const ucontext_t* context); + //! \brief Initialize exception information from a signal. + void SetExceptionFromSignal(const siginfo_t* siginfo, + const ucontext_t* context); + + //! \brief Initialize exception information from a Mach exception. + void SetExceptionFromMachException(exception_behavior_t behavior, + thread_t exception_thread, + exception_type_t exception, + const mach_exception_data_type_t* code, + mach_msg_type_number_t code_count, + thread_state_flavor_t flavor, + ConstThreadState old_state, + mach_msg_type_number_t old_state_count); + //! \brief Sets the value to be returned by ClientID(). //! //! On iOS, the client ID is under the control of the snapshot producer, diff --git a/snapshot/ios/thread_snapshot_ios.cc b/snapshot/ios/thread_snapshot_ios.cc index a5e96960..a52be51e 100644 --- a/snapshot/ios/thread_snapshot_ios.cc +++ b/snapshot/ios/thread_snapshot_ios.cc @@ -427,7 +427,12 @@ bool ThreadSnapshotIOS::Initialize(thread_t thread) { #elif defined(ARCH_CPU_ARM64) context_.architecture = kCPUArchitectureARM64; context_.arm64 = &context_arm64_; - InitializeCPUContextARM64(&context_arm64_, &thread_state, &float_state); + InitializeCPUContextARM64(&context_arm64_, + THREAD_STATE_NONE, + nullptr, + 0, + &thread_state, + &float_state); #endif INITIALIZATION_STATE_SET_VALID(initialized_); diff --git a/snapshot/ios/thread_snapshot_ios.h b/snapshot/ios/thread_snapshot_ios.h index c6dde7e6..978a8186 100644 --- a/snapshot/ios/thread_snapshot_ios.h +++ b/snapshot/ios/thread_snapshot_ios.h @@ -33,7 +33,7 @@ class ThreadSnapshotIOS final : public ThreadSnapshot { //! \brief Initializes the object. //! - //! \brief thread The mach thread used to initialize this object. + //! \brief thread The Mach thread used to initialize this object. bool Initialize(thread_t thread); //! \brief Returns an array of thread_t threads. diff --git a/snapshot/mac/cpu_context_mac.cc b/snapshot/mac/cpu_context_mac.cc index acec60ec..03893c40 100644 --- a/snapshot/mac/cpu_context_mac.cc +++ b/snapshot/mac/cpu_context_mac.cc @@ -438,11 +438,11 @@ void InitializeCPUContextX86_64(CPUContextX86_64* context, #elif defined(ARCH_CPU_ARM_FAMILY) -namespace internal { +namespace { -void InitializeCPUContextARM64(CPUContextARM64* context, - const arm_thread_state64_t* arm_thread_state64, - const arm_neon_state64_t* arm_neon_state64) { +void InitializeCPUContextARM64Thread( + CPUContextARM64* context, + const arm_thread_state64_t* arm_thread_state64) { // The structures of context->regs and arm_thread_state64->__x are laid out // identically for this copy, even though the members are organized // differently. Because of this difference, there can't be a static assert @@ -452,7 +452,10 @@ void InitializeCPUContextARM64(CPUContextARM64* context, context->pc = arm_thread_state64->__pc; context->spsr = static_cast<decltype(context->spsr)>(arm_thread_state64->__cpsr); +} +void InitializeCPUContextARM64Neon(CPUContextARM64* context, + const arm_neon_state64_t* arm_neon_state64) { static_assert(sizeof(context->fpsimd) == sizeof(arm_neon_state64->__v), "fpsimd context size mismatch"); memcpy(context->fpsimd, arm_neon_state64->__v, sizeof(arm_neon_state64->__v)); @@ -460,6 +463,107 @@ void InitializeCPUContextARM64(CPUContextARM64* context, context->fpcr = arm_neon_state64->__fpcr; } +thread_state_flavor_t InitializeCPUContextARM64Flavor( + CPUContextARM64* context, + thread_state_flavor_t flavor, + ConstThreadState state, + mach_msg_type_number_t state_count) { + mach_msg_type_number_t expected_state_count; + switch (flavor) { + case ARM_THREAD_STATE: + expected_state_count = ARM_THREAD_STATE_COUNT; + break; + case ARM_THREAD_STATE64: + expected_state_count = ARM_THREAD_STATE64_COUNT; + break; + case ARM_NEON_STATE64: + expected_state_count = ARM_NEON_STATE64_COUNT; + break; + case THREAD_STATE_NONE: { + // This may happen without error when called without exception-style + // flavor data, or even from an exception handler when the exception + // behavior is EXCEPTION_DEFAULT. + return flavor; + } + default: + LOG(WARNING) << "unhandled flavor " << flavor; + return THREAD_STATE_NONE; + } + + if (state_count < expected_state_count) { + LOG(WARNING) << "expected state_count " << expected_state_count + << " for flavor " << flavor << ", observed " << state_count; + return THREAD_STATE_NONE; + } + + switch (flavor) { + case ARM_THREAD_STATE: { + const arm_unified_thread_state_t* arm_thread_state = + reinterpret_cast<const arm_unified_thread_state_t*>(state); + if (arm_thread_state->ash.flavor != ARM_THREAD_STATE64) { + LOG(WARNING) << "expected flavor ARM_THREAD_STATE64, observed " + << arm_thread_state->ash.flavor; + return THREAD_STATE_NONE; + } + return InitializeCPUContextARM64Flavor( + context, + arm_thread_state->ash.flavor, + reinterpret_cast<ConstThreadState>(&arm_thread_state->ts_64), + arm_thread_state->ash.count); + } + + case ARM_THREAD_STATE64: { + const arm_thread_state64_t* arm_thread_state = + reinterpret_cast<const arm_thread_state64_t*>(state); + InitializeCPUContextARM64Thread(context, arm_thread_state); + return ARM_THREAD_STATE64; + } + + case ARM_NEON_STATE64: { + const arm_neon_state64_t* arm_neon_state = + reinterpret_cast<const arm_neon_state64_t*>(state); + InitializeCPUContextARM64Neon(context, arm_neon_state); + return ARM_NEON_STATE64; + } + + case THREAD_STATE_NONE: { + // This may happen without error when called without exception-style + // flavor data, or even from an exception handler when the exception + // behavior is EXCEPTION_DEFAULT. + return flavor; + } + + default: { + NOTREACHED(); + return THREAD_STATE_NONE; + } + } +} + +} // namespace + +namespace internal { + +void InitializeCPUContextARM64(CPUContextARM64* context, + thread_state_flavor_t flavor, + ConstThreadState state, + mach_msg_type_number_t state_count, + const arm_thread_state64_t* arm_thread_state64, + const arm_neon_state64_t* arm_neon_state64) { + thread_state_flavor_t set_flavor = THREAD_STATE_NONE; + if (flavor != THREAD_STATE_NONE) { + set_flavor = + InitializeCPUContextARM64Flavor(context, flavor, state, state_count); + } + + if (set_flavor != ARM_THREAD_STATE64) { + InitializeCPUContextARM64Thread(context, arm_thread_state64); + } + if (set_flavor != ARM_NEON_STATE64) { + InitializeCPUContextARM64Neon(context, arm_neon_state64); + } +} + } // namespace internal #endif diff --git a/snapshot/mac/cpu_context_mac.h b/snapshot/mac/cpu_context_mac.h index 77aedb6b..05c035a1 100644 --- a/snapshot/mac/cpu_context_mac.h +++ b/snapshot/mac/cpu_context_mac.h @@ -110,13 +110,40 @@ void InitializeCPUContextX86_64(CPUContextX86_64* context, #elif defined(ARCH_CPU_ARM_FAMILY) || DOXYGEN //! \brief Initializes a CPUContextARM64 structure from native context -//! structures. +//! structures on iOS. +//! +//! \a flavor, \a state, and \a state_count may be supplied by exception +//! handlers in order for the \a context parameter to be initialized by the +//! thread state received by the exception handler to the extent possible. In +//! that case, whatever thread state specified by these three parameters will +//! supersede \a arm_thread_state64 or \a arm_neon_state64. If thread state in +//! this format is not available, \a flavor may be set to `THREAD_STATE_NONE`, +//! and all of \a arm_thread_state64 abd \a arm_neon_state64 will be honored. +//! +//! If \a flavor, \a state, and \a state_count are provided but do not contain +//! valid values, a message will be logged and their values will be ignored as +//! though \a flavor were specified as `THREAD_STATE_NONE`. //! //! \param[out] context The CPUContextARM64 structure to initialize. +//! \param[in] flavor The native thread state flavor of \a state. This may be +//! `ARM_THREAD_STATE64`, `ARM_THREAD_STATE` or `ARM_NEON_STATE64`. It may +//! also be `THREAD_STATE_NONE` if \a state is not supplied (and is +//! `nullptr`). +//! \param[in] state The native thread state, which may be a casted pointer to +//! `arm_thread_state64_t`, `arm_unified_thread_state` or +//! `arm_neon_state64_t`. This parameter may be `nullptr` to not supply this +//! data, in which case \a flavor must be `THREAD_STATE_NONE`. If a +//! “universal” structure is used, it must carry 64-bit state data of the +//! correct type. +//! \param[in] state_count The number of `int`-sized units in \a state. This +//! may be 0 if \a state is `nullptr`. //! \param[in] arm_thread_state64 The state of the thread’s integer registers. //! \param[in] arm_neon_state64 The state of the thread’s floating-point //! registers. void InitializeCPUContextARM64(CPUContextARM64* context, + thread_state_flavor_t flavor, + ConstThreadState state, + mach_msg_type_number_t state_count, const arm_thread_state64_t* arm_thread_state64, const arm_neon_state64_t* arm_neon_state64); #endif diff --git a/snapshot/mac/exception_snapshot_mac.cc b/snapshot/mac/exception_snapshot_mac.cc index 50d1a121..8eefac9f 100644 --- a/snapshot/mac/exception_snapshot_mac.cc +++ b/snapshot/mac/exception_snapshot_mac.cc @@ -142,8 +142,13 @@ bool ExceptionSnapshotMac::Initialize(ProcessReaderMac* process_reader, thread_id_ = thread->id; - // Normally, the exception address is present in code[1] for EXC_BAD_ACCESS - // exceptions, but not for other types of exceptions. + // Normally, for EXC_BAD_ACCESS exceptions, the exception address is present + // in code[1]. It may or may not be the instruction pointer address (usually + // it’s not). code[1] may carry the exception address for other exception + // types too, but it’s not guaranteed. But for all other exception types, the + // instruction pointer will be the exception address, and in fact will be + // equal to codes[1] when it’s carrying the exception address. In those cases, + // just use the instruction pointer directly. bool code_1_is_exception_address = exception_ == EXC_BAD_ACCESS; #if defined(ARCH_CPU_X86_FAMILY) diff --git a/test/ios/host/cptest_crash_view_controller.mm b/test/ios/host/cptest_crash_view_controller.mm index 8e49b027..c4677229 100644 --- a/test/ios/host/cptest_crash_view_controller.mm +++ b/test/ios/host/cptest_crash_view_controller.mm @@ -35,8 +35,6 @@ action:@selector(throwUIGestureEnvironmentException)]; [button addGestureRecognizer:tapGesture]; [button setTranslatesAutoresizingMaskIntoConstraints:NO]; - [button.widthAnchor constraintEqualToConstant:16.0].active = YES; - [button.heightAnchor constraintEqualToConstant:16.0].active = YES; [buttonStack addArrangedSubview:button]; diff --git a/util/BUILD.gn b/util/BUILD.gn index f291f5b7..d32863ad 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -305,6 +305,7 @@ static_library("util") { "mach/mach_message.h", "mach/mach_message_server.cc", "mach/mach_message_server.h", + "misc/capture_context_mac.S", "misc/clock_mac.cc", "misc/paths_mac.cc", "synchronization/semaphore_mac.cc", @@ -337,7 +338,6 @@ static_library("util") { "mach/symbolic_constants_mach.h", "mach/task_for_pid.cc", "mach/task_for_pid.h", - "misc/capture_context_mac.S", "net/http_transport_mac.mm", "posix/process_info_mac.cc", "process/process_memory_mac.cc", diff --git a/util/misc/capture_context.h b/util/misc/capture_context.h index a88a1033..3ff71184 100644 --- a/util/misc/capture_context.h +++ b/util/misc/capture_context.h @@ -17,9 +17,7 @@ #include "build/build_config.h" -#if defined(OS_IOS) -#include <sys/ucontext.h> -#elif defined(OS_MACOSX) +#if defined(OS_MACOSX) #include <mach/mach.h> #elif defined(OS_WIN) #include <windows.h> @@ -31,11 +29,11 @@ namespace crashpad { -#if defined(OS_IOS) -using NativeCPUContext = ucontext_t; -#elif defined(OS_MACOSX) +#if defined(OS_MACOSX) #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) using NativeCPUContext = CONTEXT; From be57546feac6e014117d7336ebce673d6fd1cd29 Mon Sep 17 00:00:00 2001 From: Justin Cohen <justincohen@google.com> Date: Sat, 25 Apr 2020 22:53:51 -0400 Subject: [PATCH 397/401] ios: Fix Chromium banned warning about NULL. Change-Id: I29eefb067b171fb3d8ef9fa93c3bb146a206c9ce Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2166724 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> --- util/ios/exception_processor.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/ios/exception_processor.mm b/util/ios/exception_processor.mm index f767fb14..139a8516 100644 --- a/util/ios/exception_processor.mm +++ b/util/ios/exception_processor.mm @@ -33,6 +33,7 @@ #include <type_traits> #include <typeinfo> +#include "base/bit_cast.h" #include "base/logging.h" #include "base/strings/sys_string_conversions.h" #include "build/build_config.h" @@ -279,7 +280,7 @@ id ObjcExceptionPreprocessor(id exception) { if (!imp || imp == _objc_msgForward) { LOG(WARNING) << "Unable to find -[UIGestureEnvironment " "_deliverEvent:toGestureRecognizers:usingBlock:]"; - return reinterpret_cast<IMP>(NULL); + return bit_cast<IMP>(nullptr); // IMP is a function pointer type. } return imp; }(); From 29b1688c11df0d6a4b50d93d97be92e0e2b77b42 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Sat, 25 Apr 2020 23:35:08 -0400 Subject: [PATCH 398/401] Replace remaining uses of NULL with nullptr I did a mass conversion in 5d74f120fc57 (October 2014) but these few must have shown up after. This excludes code in third_party. Change-Id: I61cb0273804c0424904a516ed5ab735548b6b9cb Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2166725 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- test/scoped_temp_dir_win.cc | 2 +- util/file/file_io_win.cc | 2 +- util/net/http_transport_win.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/scoped_temp_dir_win.cc b/test/scoped_temp_dir_win.cc index ab4ff957..8031921c 100644 --- a/test/scoped_temp_dir_win.cc +++ b/test/scoped_temp_dir_win.cc @@ -64,7 +64,7 @@ base::FilePath ScopedTempDir::CreateTemporaryDirectory() { // the one we generate exists, keep trying another path name until we reach // some limit. base::FilePath path_to_create = GenerateCandidateName(); - if (CreateDirectory(path_to_create.value().c_str(), NULL)) + if (CreateDirectory(path_to_create.value().c_str(), nullptr)) return path_to_create; } diff --git a/util/file/file_io_win.cc b/util/file/file_io_win.cc index 7428034a..111a8da2 100644 --- a/util/file/file_io_win.cc +++ b/util/file/file_io_win.cc @@ -28,7 +28,7 @@ bool IsSocketHandle(HANDLE file) { // FILE_TYPE_PIPE means that it's a socket, a named pipe, or an anonymous // pipe. If we are unable to retrieve the pipe information, we know it's a // socket. - return !GetNamedPipeInfo(file, NULL, NULL, NULL, NULL); + return !GetNamedPipeInfo(file, nullptr, nullptr, nullptr, nullptr); } return false; } diff --git a/util/net/http_transport_win.cc b/util/net/http_transport_win.cc index 09876882..06ecc4f3 100644 --- a/util/net/http_transport_win.cc +++ b/util/net/http_transport_win.cc @@ -97,7 +97,7 @@ std::string WinHttpMessage(const char* extra) { 0, msgbuf, static_cast<DWORD>(base::size(msgbuf)), - NULL); + nullptr); if (!len) { return base::StringPrintf("%s: error 0x%lx while retrieving error 0x%lx", extra, From a5a1c3b07f4f1f70817c4a2784b244ef6e8f5316 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 27 Apr 2020 09:43:35 -0400 Subject: [PATCH 399/401] =?UTF-8?q?Add=20.style.yapf=20and=20reformat=20ac?= =?UTF-8?q?cording=20to=20yapf,=20using=20=E2=80=9Cgoogle=E2=80=9D=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % yapf --in-place $(git ls-files **/*.py) % yapf --version yapf 0.30.0 Note that this is not using the “chromium” yapf style because Chromium is moving to PEP-8. https://groups.google.com/a/chromium.org/d/topic/chromium-dev/RcJgJdkNIdg yapf 0.30.0 no longer recognizes “chromium” as a style option. https://github.com/google/yapf/commit/22ef70f3c497436adf59934b2ffa84ce6f962b88 Since this is a mass reformatting, it might as well move things all the way into the future all at once. This uses the “google” style, which is a superset of “pep8”. Change-Id: Ifa37371079ea1859e4afe8e31d2eef2cfd7af384 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2165637 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org> --- .style.yapf | 16 + build/gyp_crashpad.py | 121 +-- build/gyp_crashpad_android.py | 73 +- build/install_linux_sysroot.py | 56 +- build/ios/convert_gn_xcodeproj.py | 376 +++++----- build/ios/setup-ios-gn.py | 524 +++++++------ build/run_fuchsia_qemu.py | 161 ++-- build/run_tests.py | 1012 +++++++++++++------------- doc/support/generate_doxygen.py | 29 +- infra/config/PRESUBMIT.py | 8 +- snapshot/win/end_to_end_test.py | 794 ++++++++++---------- third_party/fuchsia/runner.py | 3 + util/mach/mig.py | 3 +- util/mach/mig_fix.py | 38 +- util/mach/mig_gen.py | 47 +- util/net/generate_test_server_key.py | 41 +- 16 files changed, 1687 insertions(+), 1615 deletions(-) create mode 100644 .style.yapf mode change 100644 => 100755 third_party/fuchsia/runner.py diff --git a/.style.yapf b/.style.yapf new file mode 100644 index 00000000..8aaf9b62 --- /dev/null +++ b/.style.yapf @@ -0,0 +1,16 @@ +# 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. + +[style] +based_on_style = google diff --git a/build/gyp_crashpad.py b/build/gyp_crashpad.py index 84856606..41ab4b94 100755 --- a/build/gyp_crashpad.py +++ b/build/gyp_crashpad.py @@ -19,83 +19,84 @@ import sys def ChooseDependencyPath(local_path, external_path): - """Chooses between a dependency located at local path and an external path. + """Chooses between a dependency located at local path and an external path. - The local path, used in standalone builds, is preferred. If it is not present - but the external path is, the external path will be used. If neither path is - present, the local path will be used, so that error messages uniformly refer - to the local path. + The local path, used in standalone builds, is preferred. If it is not + present but the external path is, the external path will be used. If neither + path is present, the local path will be used, so that error messages + uniformly refer to the local path. - Args: - local_path: The preferred local path to use for a standalone build. - external_path: The external path to fall back to. + Args: + local_path: The preferred local path to use for a standalone build. + external_path: The external path to fall back to. - Returns: - A 2-tuple. The first element is None or 'external', depending on whether - local_path or external_path was chosen. The second element is the chosen - path. - """ - if os.path.exists(local_path) or not os.path.exists(external_path): - return (None, local_path) - return ('external', external_path) + Returns: + A 2-tuple. The first element is None or 'external', depending on whether + local_path or external_path was chosen. The second element is the chosen + path. + """ + if os.path.exists(local_path) or not os.path.exists(external_path): + return (None, local_path) + return ('external', external_path) script_dir = os.path.dirname(__file__) -crashpad_dir = (os.path.dirname(script_dir) if script_dir not in ('', os.curdir) - else os.pardir) +crashpad_dir = (os.path.dirname(script_dir) + if script_dir not in ('', os.curdir) else os.pardir) -sys.path.insert(0, - ChooseDependencyPath(os.path.join(crashpad_dir, 'third_party', 'gyp', 'gyp', - 'pylib'), - os.path.join(crashpad_dir, os.pardir, os.pardir, 'gyp', - 'pylib'))[1]) +sys.path.insert( + 0, + ChooseDependencyPath( + os.path.join(crashpad_dir, 'third_party', 'gyp', 'gyp', 'pylib'), + os.path.join(crashpad_dir, os.pardir, os.pardir, 'gyp', 'pylib'))[1]) import gyp def main(args): - if 'GYP_GENERATORS' not in os.environ: - os.environ['GYP_GENERATORS'] = 'ninja' + if 'GYP_GENERATORS' not in os.environ: + os.environ['GYP_GENERATORS'] = 'ninja' - crashpad_dir_or_dot = crashpad_dir if crashpad_dir is not '' else os.curdir + crashpad_dir_or_dot = crashpad_dir if crashpad_dir is not '' else os.curdir - (dependencies, mini_chromium_common_gypi) = (ChooseDependencyPath( - os.path.join(crashpad_dir, 'third_party', 'mini_chromium', - 'mini_chromium', 'build', 'common.gypi'), - os.path.join(crashpad_dir, os.pardir, os.pardir, 'mini_chromium', - 'mini_chromium', 'build', 'common.gypi'))) - if dependencies is not None: - args.extend(['-D', 'crashpad_dependencies=%s' % dependencies]) - args.extend(['--include', mini_chromium_common_gypi]) - args.extend(['--depth', crashpad_dir_or_dot]) - args.append(os.path.join(crashpad_dir, 'crashpad.gyp')) + (dependencies, mini_chromium_common_gypi) = (ChooseDependencyPath( + os.path.join(crashpad_dir, 'third_party', 'mini_chromium', + 'mini_chromium', 'build', 'common.gypi'), + os.path.join(crashpad_dir, os.pardir, os.pardir, 'mini_chromium', + 'mini_chromium', 'build', 'common.gypi'))) + if dependencies is not None: + args.extend(['-D', 'crashpad_dependencies=%s' % dependencies]) + args.extend(['--include', mini_chromium_common_gypi]) + args.extend(['--depth', crashpad_dir_or_dot]) + args.append(os.path.join(crashpad_dir, 'crashpad.gyp')) - result = gyp.main(args) - if result != 0: - return result - - if sys.platform == 'win32': - # Check to make sure that no target_arch was specified. target_arch may be - # set during a cross build, such as a cross build for Android. - has_target_arch = False - for arg_index in range(0, len(args)): - arg = args[arg_index] - if (arg.startswith('-Dtarget_arch=') or - (arg == '-D' and arg_index + 1 < len(args) and - args[arg_index + 1].startswith('target_arch='))): - has_target_arch = True - break - - if not has_target_arch: - # Also generate the x86 build. - result = gyp.main(args + ['-D', 'target_arch=ia32', '-G', 'config=Debug']) - if result != 0: + result = gyp.main(args) + if result != 0: return result - result = gyp.main( - args + ['-D', 'target_arch=ia32', '-G', 'config=Release']) - return result + if sys.platform == 'win32': + # Check to make sure that no target_arch was specified. target_arch may + # be set during a cross build, such as a cross build for Android. + has_target_arch = False + for arg_index in range(0, len(args)): + arg = args[arg_index] + if (arg.startswith('-Dtarget_arch=') or + (arg == '-D' and arg_index + 1 < len(args) and + args[arg_index + 1].startswith('target_arch='))): + has_target_arch = True + break + + if not has_target_arch: + # Also generate the x86 build. + result = gyp.main(args + + ['-D', 'target_arch=ia32', '-G', 'config=Debug']) + if result != 0: + return result + result = gyp.main( + args + ['-D', 'target_arch=ia32', '-G', 'config=Release']) + + return result if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + sys.exit(main(sys.argv[1:])) diff --git a/build/gyp_crashpad_android.py b/build/gyp_crashpad_android.py index e17e7a26..327fa21f 100755 --- a/build/gyp_crashpad_android.py +++ b/build/gyp_crashpad_android.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# coding: utf-8 # Copyright 2017 The Crashpad Authors. All rights reserved. # @@ -25,52 +24,46 @@ import sys def main(args): - parser = argparse.ArgumentParser( - description='Set up an Android cross build', - epilog='Additional arguments will be passed to gyp_crashpad.py.') - parser.add_argument('--arch', required=True, help='Target architecture') - parser.add_argument('--api-level', required=True, help='Target API level') - parser.add_argument('--ndk', required=True, help='Standalone NDK toolchain') - (parsed, extra_command_line_args) = parser.parse_known_args(args) + parser = argparse.ArgumentParser( + description='Set up an Android cross build', + epilog='Additional arguments will be passed to gyp_crashpad.py.') + parser.add_argument('--arch', required=True, help='Target architecture') + parser.add_argument('--api-level', required=True, help='Target API level') + parser.add_argument('--ndk', required=True, help='Standalone NDK toolchain') + (parsed, extra_command_line_args) = parser.parse_known_args(args) - ndk_bin_dir = os.path.join(parsed.ndk, - 'toolchains', - 'llvm', - 'prebuilt', - 'linux-x86_64', - 'bin') - if not os.path.exists(ndk_bin_dir): - parser.error("missing toolchain") + ndk_bin_dir = os.path.join(parsed.ndk, 'toolchains', 'llvm', 'prebuilt', + 'linux-x86_64', 'bin') + if not os.path.exists(ndk_bin_dir): + parser.error("missing toolchain") - ARCH_TO_ARCH_TRIPLET = { - 'arm': 'armv7a-linux-androideabi', - 'arm64': 'aarch64-linux-android', - 'ia32': 'i686-linux-android', - 'x64': 'x86_64-linux-android', - } + ARCH_TO_ARCH_TRIPLET = { + 'arm': 'armv7a-linux-androideabi', + 'arm64': 'aarch64-linux-android', + 'ia32': 'i686-linux-android', + 'x64': 'x86_64-linux-android', + } - clang_prefix = ARCH_TO_ARCH_TRIPLET[parsed.arch] + parsed.api_level - os.environ['CC_target'] = os.path.join(ndk_bin_dir, clang_prefix + '-clang') - os.environ['CXX_target'] = os.path.join(ndk_bin_dir, clang_prefix + '-clang++') + clang_prefix = ARCH_TO_ARCH_TRIPLET[parsed.arch] + parsed.api_level + os.environ['CC_target'] = os.path.join(ndk_bin_dir, clang_prefix + '-clang') + os.environ['CXX_target'] = os.path.join(ndk_bin_dir, + clang_prefix + '-clang++') - extra_args = ['-D', 'android_api_level=' + parsed.api_level] + extra_args = ['-D', 'android_api_level=' + parsed.api_level] - # ARM only includes 'v7a' in the tool prefix for clang - tool_prefix = ('arm-linux-androideabi' if parsed.arch == 'arm' - else ARCH_TO_ARCH_TRIPLET[parsed.arch]) + # ARM only includes 'v7a' in the tool prefix for clang + tool_prefix = ('arm-linux-androideabi' if parsed.arch == 'arm' else + ARCH_TO_ARCH_TRIPLET[parsed.arch]) - for tool in ('ar', 'nm', 'readelf'): - os.environ['%s_target' % tool.upper()] = ( - os.path.join(ndk_bin_dir, '%s-%s' % (tool_prefix, tool))) + for tool in ('ar', 'nm', 'readelf'): + os.environ['%s_target' % tool.upper()] = (os.path.join( + ndk_bin_dir, '%s-%s' % (tool_prefix, tool))) - return gyp_crashpad.main( - ['-D', 'OS=android', - '-D', 'target_arch=%s' % parsed.arch, - '-D', 'clang=1', - '-f', 'ninja-android'] + - extra_args + - extra_command_line_args) + return gyp_crashpad.main([ + '-D', 'OS=android', '-D', + 'target_arch=%s' % parsed.arch, '-D', 'clang=1', '-f', 'ninja-android' + ] + extra_args + extra_command_line_args) if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + sys.exit(main(sys.argv[1:])) diff --git a/build/install_linux_sysroot.py b/build/install_linux_sysroot.py index afa88157..97f2c140 100755 --- a/build/install_linux_sysroot.py +++ b/build/install_linux_sysroot.py @@ -23,7 +23,6 @@ import subprocess import sys import urllib2 - SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) # Sysroot revision from: @@ -33,42 +32,43 @@ PATH = 'chrome-linux-sysroot/toolchain' REVISION = '3c248ba4290a5ad07085b7af07e6785bf1ae5b66' FILENAME = 'debian_stretch_amd64_sysroot.tar.xz' + def main(): - url = '%s/%s/%s/%s' % (SERVER, PATH, REVISION, FILENAME) + url = '%s/%s/%s/%s' % (SERVER, PATH, REVISION, FILENAME) - sysroot = os.path.join(SCRIPT_DIR, os.pardir, - 'third_party', 'linux', 'sysroot') + sysroot = os.path.join(SCRIPT_DIR, os.pardir, 'third_party', 'linux', + 'sysroot') - stamp = os.path.join(sysroot, '.stamp') - if os.path.exists(stamp): - with open(stamp) as s: - if s.read() == url: - return + stamp = os.path.join(sysroot, '.stamp') + if os.path.exists(stamp): + with open(stamp) as s: + if s.read() == url: + return - print 'Installing Debian root image from %s' % url + print 'Installing Debian root image from %s' % url - if os.path.isdir(sysroot): - shutil.rmtree(sysroot) - os.mkdir(sysroot) - tarball = os.path.join(sysroot, FILENAME) - print 'Downloading %s' % url + if os.path.isdir(sysroot): + shutil.rmtree(sysroot) + os.mkdir(sysroot) + tarball = os.path.join(sysroot, FILENAME) + print 'Downloading %s' % url - for _ in range(3): - response = urllib2.urlopen(url) - with open(tarball, 'wb') as f: - f.write(response.read()) - break - else: - raise Exception('Failed to download %s' % url) + for _ in range(3): + response = urllib2.urlopen(url) + with open(tarball, 'wb') as f: + f.write(response.read()) + break + else: + raise Exception('Failed to download %s' % url) - subprocess.check_call(['tar', 'xf', tarball, '-C', sysroot]) + subprocess.check_call(['tar', 'xf', tarball, '-C', sysroot]) - os.remove(tarball) + os.remove(tarball) - with open(stamp, 'w') as s: - s.write(url) + with open(stamp, 'w') as s: + s.write(url) if __name__ == '__main__': - main() - sys.exit(0) + main() + sys.exit(0) diff --git a/build/ios/convert_gn_xcodeproj.py b/build/ios/convert_gn_xcodeproj.py index b41d04ec..c00d3318 100755 --- a/build/ios/convert_gn_xcodeproj.py +++ b/build/ios/convert_gn_xcodeproj.py @@ -13,7 +13,6 @@ # 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. - """Convert GN Xcode projects to platform and configuration independent targets. GN generates Xcode projects that build one configuration only. However, typical @@ -40,234 +39,245 @@ import tempfile class XcodeProject(object): - def __init__(self, objects, counter = 0): - self.objects = objects - self.counter = 0 + def __init__(self, objects, counter=0): + self.objects = objects + self.counter = 0 - 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).hexdigest()[:24].upper() + 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).hexdigest()[:24].upper() - # Make sure ID is unique. It's possible there could be an id conflict - # since this is run after GN runs. - if new_id not in self.objects: - self.objects[new_id] = obj - return new_id + # Make sure ID is unique. It's possible there could be an id + # conflict since this is run after GN runs. + if new_id not in self.objects: + self.objects[new_id] = obj + return new_id def CopyFileIfChanged(source_path, target_path): - """Copy |source_path| to |target_path| is different.""" - target_dir = os.path.dirname(target_path) - if not os.path.isdir(target_dir): - os.makedirs(target_dir) - if not os.path.exists(target_path) or \ - not filecmp.cmp(source_path, target_path): - shutil.copyfile(source_path, target_path) + """Copy |source_path| to |target_path| is different.""" + target_dir = os.path.dirname(target_path) + if not os.path.isdir(target_dir): + os.makedirs(target_dir) + if (not os.path.exists(target_path) or + not filecmp.cmp(source_path, target_path)): + shutil.copyfile(source_path, target_path) def LoadXcodeProjectAsJSON(path): - """Return Xcode project at |path| as a JSON string.""" - return subprocess.check_output([ - 'plutil', '-convert', 'json', '-o', '-', path]) + """Return Xcode project at |path| as a JSON string.""" + return subprocess.check_output( + ['plutil', '-convert', 'json', '-o', '-', path]) def WriteXcodeProject(output_path, json_string): - """Save Xcode project to |output_path| as XML.""" - with tempfile.NamedTemporaryFile() as temp_file: - temp_file.write(json_string) - temp_file.flush() - subprocess.check_call(['plutil', '-convert', 'xml1', temp_file.name]) - CopyFileIfChanged(temp_file.name, output_path) + """Save Xcode project to |output_path| as XML.""" + with tempfile.NamedTemporaryFile() as temp_file: + temp_file.write(json_string) + temp_file.flush() + subprocess.check_call(['plutil', '-convert', 'xml1', temp_file.name]) + CopyFileIfChanged(temp_file.name, output_path) def UpdateProductsProject(file_input, file_output, configurations, root_dir): - """Update Xcode project to support multiple configurations. + """Update Xcode project to support multiple configurations. - Args: - file_input: path to the input Xcode project - file_output: path to the output file - configurations: list of string corresponding to the configurations that - need to be supported by the tweaked Xcode projects, must contains at - least one value. - """ - json_data = json.loads(LoadXcodeProjectAsJSON(file_input)) - project = XcodeProject(json_data['objects']) + Args: + file_input: path to the input Xcode project + file_output: path to the output file + configurations: list of string corresponding to the configurations that + need to be supported by the tweaked Xcode projects, must contains at + least one value. + """ + json_data = json.loads(LoadXcodeProjectAsJSON(file_input)) + project = XcodeProject(json_data['objects']) - objects_to_remove = [] - for value in project.objects.values(): - isa = value['isa'] + objects_to_remove = [] + for value in project.objects.values(): + isa = value['isa'] - # Teach build shell script to look for the configuration and platform. - if isa == 'PBXShellScriptBuildPhase': - value['shellScript'] = value['shellScript'].replace( - 'ninja -C .', - 'ninja -C "../${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}"') + # Teach build shell script to look for the configuration and platform. + if isa == 'PBXShellScriptBuildPhase': + value['shellScript'] = value['shellScript'].replace( + 'ninja -C .', + 'ninja -C "../${CONFIGURATION}${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']) + # 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)' - build_config_template['buildSettings']['CODE_SIGN_IDENTITY'] = '' + build_config_template = project.objects[value['buildConfigurations'] + [0]] + build_settings = build_config_template['buildSettings'] + build_settings['CONFIGURATION_BUILD_DIR'] = ( + '$(PROJECT_DIR)/../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)') + build_settings['CODE_SIGN_IDENTITY'] = '' - 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)) + 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)) - for object_id in objects_to_remove: - del project.objects[object_id] + for object_id in objects_to_remove: + del project.objects[object_id] - AddMarkdownToProject(project, root_dir, json_data['rootObject']) + AddMarkdownToProject(project, root_dir, json_data['rootObject']) - objects = collections.OrderedDict(sorted(project.objects.iteritems())) - WriteXcodeProject(file_output, json.dumps(json_data)) + objects = collections.OrderedDict(sorted(project.objects.iteritems())) + WriteXcodeProject(file_output, json.dumps(json_data)) def AddMarkdownToProject(project, root_dir, root_object): - list_files_cmd = ['git', '-C', root_dir, 'ls-files', '*.md'] - paths = subprocess.check_output(list_files_cmd).splitlines() - ios_internal_dir = os.path.join(root_dir, 'ios_internal') - if os.path.exists(ios_internal_dir): - list_files_cmd = ['git', '-C', ios_internal_dir, 'ls-files', '*.md'] - ios_paths = subprocess.check_output(list_files_cmd).splitlines() - paths.extend(["ios_internal/" + path for path in ios_paths]) - for path in paths: - new_markdown_entry = { - "fileEncoding": "4", - "isa": "PBXFileReference", - "lastKnownFileType": "net.daringfireball.markdown", - "name": os.path.basename(path), - "path": path, - "sourceTree": "<group>" - } - new_markdown_entry_id = project.AddObject('sources', new_markdown_entry) - folder = GetFolderForPath(project, root_object, os.path.dirname(path)) - folder['children'].append(new_markdown_entry_id) + list_files_cmd = ['git', '-C', root_dir, 'ls-files', '*.md'] + paths = subprocess.check_output(list_files_cmd).splitlines() + ios_internal_dir = os.path.join(root_dir, 'ios_internal') + if os.path.exists(ios_internal_dir): + list_files_cmd = ['git', '-C', ios_internal_dir, 'ls-files', '*.md'] + ios_paths = subprocess.check_output(list_files_cmd).splitlines() + paths.extend(["ios_internal/" + path for path in ios_paths]) + for path in paths: + new_markdown_entry = { + "fileEncoding": "4", + "isa": "PBXFileReference", + "lastKnownFileType": "net.daringfireball.markdown", + "name": os.path.basename(path), + "path": path, + "sourceTree": "<group>" + } + new_markdown_entry_id = project.AddObject('sources', new_markdown_entry) + folder = GetFolderForPath(project, root_object, os.path.dirname(path)) + folder['children'].append(new_markdown_entry_id) def GetFolderForPath(project, rootObject, path): - objects = project.objects - # 'Sources' is always the first child of - # project->rootObject->mainGroup->children. - root = objects[objects[objects[rootObject]['mainGroup']]['children'][0]] - if not path: + objects = project.objects + # 'Sources' is always the first child of + # project->rootObject->mainGroup->children. + root = objects[objects[objects[rootObject]['mainGroup']]['children'][0]] + if not path: + return root + for folder in path.split('/'): + children = root['children'] + new_root = None + for child in children: + if (objects[child]['isa'] == 'PBXGroup' and + objects[child]['name'] == folder): + new_root = objects[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_group = { + "children": [], + "isa": "PBXGroup", + "name": folder, + "sourceTree": "<group>" + } + new_group_id = project.AddObject('sources', new_group) + children.append(new_group_id) + new_root = objects[new_group_id] + root = new_root return root - for folder in path.split('/'): - children = root['children'] - new_root = None - for child in children: - if objects[child]['isa'] == 'PBXGroup' and \ - objects[child]['name'] == folder: - new_root = objects[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_group = { - "children": [ - ], - "isa": "PBXGroup", - "name": folder, - "sourceTree": "<group>" - } - new_group_id = project.AddObject('sources', new_group) - children.append(new_group_id) - new_root = objects[new_group_id] - root = new_root - return root def DisableNewBuildSystem(output_dir): - """Disables the new build system due to crbug.com/852522 """ - xcwspacesharedsettings = os.path.join(output_dir, 'all.xcworkspace', - 'xcshareddata', 'WorkspaceSettings.xcsettings') - if os.path.isfile(xcwspacesharedsettings): - json_data = json.loads(LoadXcodeProjectAsJSON(xcwspacesharedsettings)) - else: - json_data = {} - json_data['BuildSystemType'] = 'Original' - WriteXcodeProject(xcwspacesharedsettings, json.dumps(json_data)) + """Disables the new build system due to crbug.com/852522 """ + xcwspacesharedsettings = os.path.join(output_dir, 'all.xcworkspace', + 'xcshareddata', + 'WorkspaceSettings.xcsettings') + if os.path.isfile(xcwspacesharedsettings): + json_data = json.loads(LoadXcodeProjectAsJSON(xcwspacesharedsettings)) + else: + json_data = {} + json_data['BuildSystemType'] = 'Original' + WriteXcodeProject(xcwspacesharedsettings, json.dumps(json_data)) def ConvertGnXcodeProject(root_dir, input_dir, output_dir, configurations): - '''Tweak the Xcode project generated by gn to support multiple configurations. + '''Tweak the Xcode project generated by gn to support multiple + configurations. - The Xcode projects generated by "gn gen --ide" only supports a single - platform and configuration (as the platform and configuration are set - per output directory). This method takes as input such projects and - add support for multiple configurations and platforms (to allow devs - to select them in Xcode). + The Xcode projects generated by "gn gen --ide" only supports a single + platform and configuration (as the platform and configuration are set per + output directory). This method takes as input such projects and add support + for multiple configurations and platforms (to allow devs to select them in + Xcode). - Args: - 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. - ''' - # Update products project. - products = os.path.join('products.xcodeproj', 'project.pbxproj') - product_input = os.path.join(input_dir, products) - product_output = os.path.join(output_dir, products) - UpdateProductsProject(product_input, product_output, configurations, root_dir) + Args: + 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. + ''' + # Update products project. + products = os.path.join('products.xcodeproj', 'project.pbxproj') + product_input = os.path.join(input_dir, products) + product_output = os.path.join(output_dir, products) + UpdateProductsProject(product_input, product_output, configurations, + root_dir) - # Copy all workspace. - xcwspace = os.path.join('all.xcworkspace', 'contents.xcworkspacedata') - CopyFileIfChanged(os.path.join(input_dir, xcwspace), - os.path.join(output_dir, xcwspace)) + # Copy all workspace. + xcwspace = os.path.join('all.xcworkspace', 'contents.xcworkspacedata') + CopyFileIfChanged(os.path.join(input_dir, xcwspace), + os.path.join(output_dir, xcwspace)) - # TODO(crbug.com/852522): Disable new BuildSystemType. - DisableNewBuildSystem(output_dir) + # TODO(crbug.com/852522): Disable new BuildSystemType. + DisableNewBuildSystem(output_dir) + + # TODO(crbug.com/679110): gn has been modified to remove 'sources.xcodeproj' + # and keep 'all.xcworkspace' and 'products.xcodeproj'. The following code is + # here to support both old and new projects setup and will be removed once + # gn has rolled past it. + sources = os.path.join('sources.xcodeproj', 'project.pbxproj') + if os.path.isfile(os.path.join(input_dir, sources)): + CopyFileIfChanged(os.path.join(input_dir, sources), + os.path.join(output_dir, sources)) - # TODO(crbug.com/679110): gn has been modified to remove 'sources.xcodeproj' - # and keep 'all.xcworkspace' and 'products.xcodeproj'. The following code is - # here to support both old and new projects setup and will be removed once gn - # has rolled past it. - sources = os.path.join('sources.xcodeproj', 'project.pbxproj') - if os.path.isfile(os.path.join(input_dir, sources)): - CopyFileIfChanged(os.path.join(input_dir, sources), - os.path.join(output_dir, sources)) def Main(args): - parser = argparse.ArgumentParser( - description='Convert GN Xcode projects for iOS.') - parser.add_argument( - 'input', - help='directory containing [product|all] Xcode projects.') - parser.add_argument( - 'output', - help='directory where to generate the iOS configuration.') - parser.add_argument( - '--add-config', dest='configurations', default=[], action='append', - help='configuration to add to the Xcode project') - parser.add_argument( - '--root', type=os.path.abspath, required=True, - help='root directory of the project') - args = parser.parse_args(args) + parser = argparse.ArgumentParser( + description='Convert GN Xcode projects for iOS.') + parser.add_argument( + 'input', help='directory containing [product|all] Xcode projects.') + parser.add_argument( + 'output', help='directory where to generate the iOS configuration.') + parser.add_argument('--add-config', + dest='configurations', + default=[], + action='append', + help='configuration to add to the Xcode project') + parser.add_argument('--root', + type=os.path.abspath, + required=True, + help='root directory of the project') + args = parser.parse_args(args) - if not os.path.isdir(args.input): - sys.stderr.write('Input directory does not exists.\n') - return 1 + if not os.path.isdir(args.input): + sys.stderr.write('Input directory does not exists.\n') + return 1 - required = set(['products.xcodeproj', 'all.xcworkspace']) - if not required.issubset(os.listdir(args.input)): - sys.stderr.write( - 'Input directory does not contain all necessary Xcode projects.\n') - return 1 + required = set(['products.xcodeproj', 'all.xcworkspace']) + if not required.issubset(os.listdir(args.input)): + sys.stderr.write( + 'Input directory does not contain all necessary Xcode projects.\n') + return 1 - if not args.configurations: - sys.stderr.write('At least one configuration required, see --add-config.\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.input, args.output, args.configurations) if __name__ == '__main__': - sys.exit(Main(sys.argv[1:])) + sys.exit(Main(sys.argv[1:])) diff --git a/build/ios/setup-ios-gn.py b/build/ios/setup-ios-gn.py index 995e3c84..934b67c6 100755 --- a/build/ios/setup-ios-gn.py +++ b/build/ios/setup-ios-gn.py @@ -14,7 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - import argparse import convert_gn_xcodeproj import errno @@ -27,326 +26,325 @@ import tempfile import ConfigParser try: - import cStringIO as StringIO + import cStringIO as StringIO except ImportError: - import StringIO - + import StringIO SUPPORTED_TARGETS = ('iphoneos', 'iphonesimulator') SUPPORTED_CONFIGS = ('Debug', 'Release', 'Profile', 'Official', 'Coverage') class ConfigParserWithStringInterpolation(ConfigParser.SafeConfigParser): + '''A .ini file parser that supports strings and environment variables.''' - '''A .ini file parser that supports strings and environment variables.''' + ENV_VAR_PATTERN = re.compile(r'\$([A-Za-z0-9_]+)') - ENV_VAR_PATTERN = re.compile(r'\$([A-Za-z0-9_]+)') + def values(self, section): + return map(lambda (k, v): self._UnquoteString(self._ExpandEnvVar(v)), + ConfigParser.SafeConfigParser.items(self, section)) - def values(self, section): - return map( - lambda (k, v): self._UnquoteString(self._ExpandEnvVar(v)), - ConfigParser.SafeConfigParser.items(self, section)) + def getstring(self, section, option): + return self._UnquoteString(self._ExpandEnvVar(self.get(section, + option))) - def getstring(self, section, option): - return self._UnquoteString(self._ExpandEnvVar(self.get(section, option))) + def _UnquoteString(self, string): + if not string or string[0] != '"' or string[-1] != '"': + return string + return string[1:-1] - 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 - 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.''' - '''Holds configuration for a build and method to generate gn default files.''' + FAT_BUILD_DEFAULT_ARCH = '64-bit' - FAT_BUILD_DEFAULT_ARCH = '64-bit' - - TARGET_CPU_VALUES = { - 'iphoneos': { - '32-bit': '"arm"', - '64-bit': '"arm64"', - }, - 'iphonesimulator': { - '32-bit': '"x86"', - '64-bit': '"x64"', + 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 __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. + 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 = [] + 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'))) + args.append(('is_debug', self._config in ('Debug', 'Coverage'))) - if os.environ.get('FORCE_MAC_TOOLCHAIN', '0') == '1': - args.append(('use_system_xcode', False)) + 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.itervalues() 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 = StringIO.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 = StringIO.StringIO() - self.WriteArgsGn(buf) - WriteToFileIfChanged( - os.path.join(out_path, 'args.gn'), - buf.getvalue(), - overwrite=True) - - buf = StringIO.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 = StringIO.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') - - 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 = ' ' + 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.itervalues() if cpu != target_cpu])) 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') - else: - stream.write('%s = %s\n' % (name, value)) + args.append(('target_cpu', cpu_values[build_arch])) - 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') + # 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 WriteBuildNinjaDeps(self, stream): - stream.write('build.ninja: nonexistant_file.gn\n') + def Generate(self, gn_path, root_path, out_path): + buf = StringIO.StringIO() + self.WriteArgsGn(buf) + WriteToFileIfChanged(os.path.join(out_path, 'args.gn'), + buf.getvalue(), + overwrite=True) - 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') - if self._settings.getboolean('goma', 'enabled'): - ninja_jobs = self._settings.getint('xcode', 'jobs') or 200 - gn_command.append('--ninja-extra-args=-j%s' % ninja_jobs) - if self._settings.has_section('filters'): - target_filters = self._settings.values('filters') - if target_filters: - gn_command.append('--filters=%s' % ';'.join(target_filters)) - # TODO(justincohen): --check is currently failing in crashpad. - # 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 + subprocess.check_call( + self.GetGnCommand(gn_path, root_path, out_path, True)) + + def CreateGnRules(self, gn_path, root_path, out_path): + buf = StringIO.StringIO() + self.WriteArgsGn(buf) + WriteToFileIfChanged(os.path.join(out_path, 'args.gn'), + buf.getvalue(), + overwrite=True) + + buf = StringIO.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 = StringIO.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') + + 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') + 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('--root-target=gn_all') + if self._settings.getboolean('goma', 'enabled'): + ninja_jobs = self._settings.getint('xcode', 'jobs') or 200 + gn_command.append('--ninja-extra-args=-j%s' % ninja_jobs) + if self._settings.has_section('filters'): + target_filters = self._settings.values('filters') + if target_filters: + gn_command.append('--filters=%s' % ';'.join(target_filters)) + # TODO(justincohen): --check is currently failing in crashpad. + # 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) + '''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) 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 + '''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.''' + '''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) + 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) 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)) + 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)) + 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') - args = parser.parse_args(args) + 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') + 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'), - ]) + # 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) + # 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) + # 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) - if settings.getboolean('goma', 'enabled'): - if settings.getint('xcode', 'jobs') < 0: - sys.stderr.write('ERROR: invalid value for xcode.jobs: %s\n' % - settings.get('xcode', 'jobs')) - sys.exit(1) - goma_install = os.path.expanduser(settings.getstring('goma', 'install')) - if not os.path.isdir(goma_install): - sys.stderr.write('WARNING: goma.install directory not found: %s\n' % - settings.get('goma', 'install')) - sys.stderr.write('WARNING: disabling goma\n') - settings.set('goma', 'enabled', 'false') + if settings.getboolean('goma', 'enabled'): + if settings.getint('xcode', 'jobs') < 0: + sys.stderr.write('ERROR: invalid value for xcode.jobs: %s\n' % + settings.get('xcode', 'jobs')) + sys.exit(1) + goma_install = os.path.expanduser(settings.getstring('goma', 'install')) + if not os.path.isdir(goma_install): + sys.stderr.write('WARNING: goma.install directory not found: %s\n' % + settings.get('goma', 'install')) + sys.stderr.write('WARNING: disabling goma\n') + settings.set('goma', 'enabled', 'false') - # Find gn binary in PATH. - gn_path = FindGn() - if gn_path is None: - sys.stderr.write('ERROR: cannot find gn in PATH\n') - sys.exit(1) + # Find gn binary in PATH. + 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, 'out') - if not os.path.isdir(out_dir): - os.makedirs(out_dir) + out_dir = os.path.join(args.root, 'out') + 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) + GenerateXcodeProject(gn_path, 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/run_fuchsia_qemu.py b/build/run_fuchsia_qemu.py index 135b314e..aff0efd8 100755 --- a/build/run_fuchsia_qemu.py +++ b/build/run_fuchsia_qemu.py @@ -13,7 +13,6 @@ # 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. - """Helper script to [re]start or stop a helper Fuchsia QEMU instance to be used for running tests without a device. """ @@ -30,105 +29,117 @@ import tempfile import time try: - from subprocess import DEVNULL + from subprocess import DEVNULL except ImportError: - DEVNULL = open(os.devnull, 'r+b') + DEVNULL = open(os.devnull, 'r+b') CRASHPAD_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir) def _Stop(pid_file): - if os.path.isfile(pid_file): - with open(pid_file, 'rb') as f: - pid = int(f.read().strip()) - try: - os.kill(pid, signal.SIGTERM) - except: - print('Unable to kill pid %d, continuing' % pid, file=sys.stderr) - os.unlink(pid_file) + if os.path.isfile(pid_file): + with open(pid_file, 'rb') as f: + pid = int(f.read().strip()) + try: + os.kill(pid, signal.SIGTERM) + except: + print('Unable to kill pid %d, continuing' % pid, file=sys.stderr) + os.unlink(pid_file) def _CheckForTun(): - """Check for networking. TODO(scottmg): Currently, this is Linux-specific. - """ - returncode = subprocess.call( - ['tunctl', '-b', '-u', getpass.getuser(), '-t', 'qemu'], - stdout=DEVNULL, stderr=DEVNULL) - if returncode != 0: - print('To use QEMU with networking on Linux, configure TUN/TAP. See:', - file=sys.stderr) - print(' https://fuchsia.googlesource.com/zircon/+/HEAD/docs/qemu.md#enabling-networking-under-qemu-x86_64-only', - file=sys.stderr) - return 2 - return 0 + """Check for networking. TODO(scottmg): Currently, this is Linux-specific. + """ + returncode = subprocess.call( + ['tunctl', '-b', '-u', + getpass.getuser(), '-t', 'qemu'], + stdout=DEVNULL, + stderr=DEVNULL) + if returncode != 0: + print('To use QEMU with networking on Linux, configure TUN/TAP. See:', + file=sys.stderr) + print( + ' https://fuchsia.googlesource.com/zircon/+/HEAD/docs/qemu.md#enabling-networking-under-qemu-x86_64-only', + file=sys.stderr) + return 2 + return 0 def _Start(pid_file): - tun_result = _CheckForTun() - if tun_result != 0: - return tun_result + tun_result = _CheckForTun() + if tun_result != 0: + return tun_result - arch = 'mac-amd64' if sys.platform == 'darwin' else 'linux-amd64' - fuchsia_dir = os.path.join(CRASHPAD_ROOT, 'third_party', 'fuchsia') - qemu_path = os.path.join(fuchsia_dir, 'qemu', arch, 'bin', - 'qemu-system-x86_64') - kernel_data_dir = os.path.join(fuchsia_dir, 'sdk', arch, 'target', 'x86_64') - kernel_path = os.path.join(kernel_data_dir, 'zircon.bin') - initrd_path = os.path.join(kernel_data_dir, 'bootdata.bin') + arch = 'mac-amd64' if sys.platform == 'darwin' else 'linux-amd64' + fuchsia_dir = os.path.join(CRASHPAD_ROOT, 'third_party', 'fuchsia') + qemu_path = os.path.join(fuchsia_dir, 'qemu', arch, 'bin', + 'qemu-system-x86_64') + kernel_data_dir = os.path.join(fuchsia_dir, 'sdk', arch, 'target', 'x86_64') + kernel_path = os.path.join(kernel_data_dir, 'zircon.bin') + initrd_path = os.path.join(kernel_data_dir, 'bootdata.bin') - mac_tail = ':'.join('%02x' % random.randint(0, 255) for x in range(3)) - instance_name = 'crashpad_qemu_' + \ - ''.join(chr(random.randint(ord('A'), ord('Z'))) for x in range(8)) + mac_tail = ':'.join('%02x' % random.randint(0, 255) for x in range(3)) + instance_name = ( + 'crashpad_qemu_' + + ''.join(chr(random.randint(ord('A'), ord('Z'))) for x in range(8))) - # These arguments are from the Fuchsia repo in zircon/scripts/run-zircon. - popen = subprocess.Popen([ - qemu_path, - '-m', '2048', - '-nographic', - '-kernel', kernel_path, - '-initrd', initrd_path, - '-smp', '4', - '-serial', 'stdio', - '-monitor', 'none', - '-machine', 'q35', - '-cpu', 'host,migratable=no', - '-enable-kvm', - '-netdev', 'type=tap,ifname=qemu,script=no,downscript=no,id=net0', - '-device', 'e1000,netdev=net0,mac=52:54:00:' + mac_tail, - '-append', 'TERM=dumb zircon.nodename=' + instance_name, - ], stdin=DEVNULL, stdout=DEVNULL, stderr=DEVNULL) + # These arguments are from the Fuchsia repo in zircon/scripts/run-zircon. - with open(pid_file, 'wb') as f: - f.write('%d\n' % popen.pid) + # yapf: disable + popen = subprocess.Popen([ + qemu_path, + '-m', '2048', + '-nographic', + '-kernel', kernel_path, + '-initrd', initrd_path, + '-smp', '4', + '-serial', 'stdio', + '-monitor', 'none', + '-machine', 'q35', + '-cpu', 'host,migratable=no', + '-enable-kvm', + '-netdev', 'type=tap,ifname=qemu,script=no,downscript=no,id=net0', + '-device', 'e1000,netdev=net0,mac=52:54:00:' + mac_tail, + '-append', 'TERM=dumb zircon.nodename=' + instance_name, + ], + stdin=DEVNULL, + stdout=DEVNULL, + stderr=DEVNULL) + # yapf: enable - for i in range(10): - netaddr_path = os.path.join(fuchsia_dir, 'sdk', arch, 'tools', 'netaddr') - if subprocess.call([netaddr_path, '--nowait', instance_name], - stdout=open(os.devnull), stderr=open(os.devnull)) == 0: - break - time.sleep(.5) - else: - print('instance did not respond after start', file=sys.stderr) - return 1 + with open(pid_file, 'wb') as f: + f.write('%d\n' % popen.pid) - return 0 + for i in range(10): + netaddr_path = os.path.join(fuchsia_dir, 'sdk', arch, 'tools', + 'netaddr') + if subprocess.call([netaddr_path, '--nowait', instance_name], + stdout=open(os.devnull), + stderr=open(os.devnull)) == 0: + break + time.sleep(.5) + else: + print('instance did not respond after start', file=sys.stderr) + return 1 + + return 0 def main(args): - if len(args) != 1 or args[0] not in ('start', 'stop'): - print('usage: run_fuchsia_qemu.py start|stop', file=sys.stderr) - return 1 + if len(args) != 1 or args[0] not in ('start', 'stop'): + print('usage: run_fuchsia_qemu.py start|stop', file=sys.stderr) + return 1 - command = args[0] + command = args[0] - pid_file = os.path.join(tempfile.gettempdir(), 'crashpad_fuchsia_qemu_pid') - _Stop(pid_file) - if command == 'start': - return _Start(pid_file) + pid_file = os.path.join(tempfile.gettempdir(), 'crashpad_fuchsia_qemu_pid') + _Stop(pid_file) + if command == 'start': + return _Start(pid_file) - return 0 + return 0 if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + sys.exit(main(sys.argv[1:])) diff --git a/build/run_tests.py b/build/run_tests.py index 38473cd0..2f1919b5 100755 --- a/build/run_tests.py +++ b/build/run_tests.py @@ -33,579 +33,603 @@ IS_WINDOWS_HOST = sys.platform.startswith('win') def _FindGNFromBinaryDir(binary_dir): - """Attempts to determine the path to a GN binary used to generate the build - files in the given binary_dir. This is necessary because `gn` might not be in - the path or might be in a non-standard location, particularly on build - machines.""" + """Attempts to determine the path to a GN binary used to generate the build + files in the given binary_dir. This is necessary because `gn` might not be + in the path or might be in a non-standard location, particularly on build + machines.""" - build_ninja = os.path.join(binary_dir, 'build.ninja') - if os.path.isfile(build_ninja): - with open(build_ninja, 'rb') as f: - # Look for the always-generated regeneration rule of the form: - # - # rule gn - # command = <gn binary> ... arguments ... - # - # to extract the gn binary's full path. - found_rule_gn = False - for line in f: - if line.strip() == 'rule gn': - found_rule_gn = True - continue - if found_rule_gn: - if len(line) == 0 or line[0] != ' ': - return None - if line.startswith(' command = '): - gn_command_line_parts = line.strip().split(' ') - if len(gn_command_line_parts) > 2: - return os.path.join(binary_dir, gn_command_line_parts[2]) + build_ninja = os.path.join(binary_dir, 'build.ninja') + if os.path.isfile(build_ninja): + with open(build_ninja, 'rb') as f: + # Look for the always-generated regeneration rule of the form: + # + # rule gn + # command = <gn binary> ... arguments ... + # + # to extract the gn binary's full path. + found_rule_gn = False + for line in f: + if line.strip() == 'rule gn': + found_rule_gn = True + continue + if found_rule_gn: + if len(line) == 0 or line[0] != ' ': + return None + if line.startswith(' command = '): + gn_command_line_parts = line.strip().split(' ') + if len(gn_command_line_parts) > 2: + return os.path.join(binary_dir, + gn_command_line_parts[2]) - return None + return None def _BinaryDirTargetOS(binary_dir): - """Returns the apparent target OS of binary_dir, or None if none appear to be - explicitly specified.""" + """Returns the apparent target OS of binary_dir, or None if none appear to + be explicitly specified.""" - gn_path = _FindGNFromBinaryDir(binary_dir) + gn_path = _FindGNFromBinaryDir(binary_dir) - if gn_path: - # Look for a GN “target_os”. - popen = subprocess.Popen([gn_path, '--root=' + CRASHPAD_DIR, - 'args', binary_dir, - '--list=target_os', '--short'], - shell=IS_WINDOWS_HOST, - stdout=subprocess.PIPE, stderr=open(os.devnull)) - value = popen.communicate()[0] - if popen.returncode == 0: - match = re.match('target_os = "(.*)"$', value.decode('utf-8')) - if match: - return match.group(1) + if gn_path: + # Look for a GN “target_os”. + popen = subprocess.Popen([ + gn_path, '--root=' + CRASHPAD_DIR, 'args', binary_dir, + '--list=target_os', '--short' + ], + shell=IS_WINDOWS_HOST, + stdout=subprocess.PIPE, + stderr=open(os.devnull)) + value = popen.communicate()[0] + if popen.returncode == 0: + match = re.match('target_os = "(.*)"$', value.decode('utf-8')) + if match: + return match.group(1) - # For GYP with Ninja, look for the appearance of “linux-android” in the path - # to ar. This path is configured by gyp_crashpad_android.py. - build_ninja_path = os.path.join(binary_dir, 'build.ninja') - if os.path.exists(build_ninja_path): - with open(build_ninja_path) as build_ninja_file: - build_ninja_content = build_ninja_file.read() - match = re.search('-linux-android(eabi)?-ar$', - build_ninja_content, - re.MULTILINE) - if match: - return 'android' + # For GYP with Ninja, look for the appearance of “linux-android” in the path + # to ar. This path is configured by gyp_crashpad_android.py. + build_ninja_path = os.path.join(binary_dir, 'build.ninja') + if os.path.exists(build_ninja_path): + with open(build_ninja_path) as build_ninja_file: + build_ninja_content = build_ninja_file.read() + match = re.search('-linux-android(eabi)?-ar$', build_ninja_content, + re.MULTILINE) + if match: + return 'android' - return None + return None def _EnableVTProcessingOnWindowsConsole(): - """Enables virtual terminal processing for ANSI/VT100-style escape sequences - on a Windows console attached to standard output. Returns True on success. - Returns False if standard output is not a console or if virtual terminal - processing is not supported. The feature was introduced in Windows 10. - """ + """Enables virtual terminal processing for ANSI/VT100-style escape sequences + on a Windows console attached to standard output. Returns True on success. + Returns False if standard output is not a console or if virtual terminal + processing is not supported. The feature was introduced in Windows 10. + """ - import pywintypes - import win32console - import winerror + import pywintypes + import win32console + import winerror - stdout_console = win32console.GetStdHandle(win32console.STD_OUTPUT_HANDLE) - try: - console_mode = stdout_console.GetConsoleMode() - except pywintypes.error as e: - if e.winerror == winerror.ERROR_INVALID_HANDLE: - # Standard output is not a console. - return False - raise + stdout_console = win32console.GetStdHandle(win32console.STD_OUTPUT_HANDLE) + try: + console_mode = stdout_console.GetConsoleMode() + except pywintypes.error as e: + if e.winerror == winerror.ERROR_INVALID_HANDLE: + # Standard output is not a console. + return False + raise - try: - # From <wincon.h>. This would be - # win32console.ENABLE_VIRTUAL_TERMINAL_PROCESSING, but it’s too new to be - # defined there. - ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 + try: + # From <wincon.h>. This would be + # win32console.ENABLE_VIRTUAL_TERMINAL_PROCESSING, but it’s too new to + # be defined there. + ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 - stdout_console.SetConsoleMode(console_mode | - ENABLE_VIRTUAL_TERMINAL_PROCESSING) - except pywintypes.error as e: - if e.winerror == winerror.ERROR_INVALID_PARAMETER: - # ANSI/VT100-style escape sequence processing isn’t supported before - # Windows 10. - return False - raise + stdout_console.SetConsoleMode(console_mode | + ENABLE_VIRTUAL_TERMINAL_PROCESSING) + except pywintypes.error as e: + if e.winerror == winerror.ERROR_INVALID_PARAMETER: + # ANSI/VT100-style escape sequence processing isn’t supported before + # Windows 10. + return False + raise - return True + return True def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): - local_test_path = os.path.join(binary_dir, test) - MAYBE_UNSUPPORTED_TESTS = ( - 'crashpad_client_test', - 'crashpad_handler_test', - 'crashpad_minidump_test', - 'crashpad_snapshot_test', - ) - if not os.path.exists(local_test_path) and test in MAYBE_UNSUPPORTED_TESTS: - print('This test is not present and may not be supported, skipping') - return + local_test_path = os.path.join(binary_dir, test) + MAYBE_UNSUPPORTED_TESTS = ( + 'crashpad_client_test', + 'crashpad_handler_test', + 'crashpad_minidump_test', + 'crashpad_snapshot_test', + ) + if not os.path.exists(local_test_path) and test in MAYBE_UNSUPPORTED_TESTS: + print('This test is not present and may not be supported, skipping') + return - def _adb(*args): - # Flush all of this script’s own buffered stdout output before running adb, - # which will likely produce its own output on stdout. - sys.stdout.flush() + def _adb(*args): + # Flush all of this script’s own buffered stdout output before running + # adb, which will likely produce its own output on stdout. + sys.stdout.flush() - adb_command = ['adb', '-s', android_device] - adb_command.extend(args) - subprocess.check_call(adb_command, shell=IS_WINDOWS_HOST) + adb_command = ['adb', '-s', android_device] + adb_command.extend(args) + subprocess.check_call(adb_command, shell=IS_WINDOWS_HOST) - def _adb_push(sources, destination): - args = list(sources) - args.append(destination) - _adb('push', *args) + def _adb_push(sources, destination): + args = list(sources) + args.append(destination) + _adb('push', *args) - def _adb_shell(command_args, env={}): - # Build a command to execute via “sh -c” instead of invoking it directly. - # Here’s why: - # - # /system/bin/env isn’t normally present prior to Android 6.0 (M), where - # toybox was introduced (Android platform/manifest 9a2c01e8450b). Instead, - # set environment variables by using the shell’s internal “export” command. - # - # adbd prior to Android 7.0 (N), and the adb client prior to SDK - # platform-tools version 24, don’t know how to communicate a shell command’s - # exit status. This was added in Android platform/system/core 606835ae5c4b). - # With older adb servers and clients, adb will “exit 0” indicating success - # even if the command failed on the device. This makes - # subprocess.check_call() semantics difficult to implement directly. As a - # workaround, have the device send the command’s exit status over stdout and - # pick it back up in this function. - # - # Both workarounds are implemented by giving the device a simple script, - # which adbd will run as an “sh -c” argument. - adb_command = ['adb', '-s', android_device, 'shell'] - script_commands = [] - for k, v in env.items(): - script_commands.append('export %s=%s' % (pipes.quote(k), pipes.quote(v))) - script_commands.extend([ - ' '.join(pipes.quote(x) for x in command_args), - 'status=${?}', - 'echo "status=${status}"', - 'exit ${status}']) - adb_command.append('; '.join(script_commands)) - child = subprocess.Popen(adb_command, - shell=IS_WINDOWS_HOST, - stdin=open(os.devnull), - stdout=subprocess.PIPE) + def _adb_shell(command_args, env={}): + # Build a command to execute via “sh -c” instead of invoking it + # directly. Here’s why: + # + # /system/bin/env isn’t normally present prior to Android 6.0 (M), where + # toybox was introduced (Android platform/manifest 9a2c01e8450b). + # Instead, set environment variables by using the shell’s internal + # “export” command. + # + # adbd prior to Android 7.0 (N), and the adb client prior to SDK + # platform-tools version 24, don’t know how to communicate a shell + # command’s exit status. This was added in Android platform/system/core + # 606835ae5c4b). With older adb servers and clients, adb will “exit 0” + # indicating success even if the command failed on the device. This + # makes subprocess.check_call() semantics difficult to implement + # directly. As a workaround, have the device send the command’s exit + # status over stdout and pick it back up in this function. + # + # Both workarounds are implemented by giving the device a simple script, + # which adbd will run as an “sh -c” argument. + adb_command = ['adb', '-s', android_device, 'shell'] + script_commands = [] + for k, v in env.items(): + script_commands.append('export %s=%s' % + (pipes.quote(k), pipes.quote(v))) + script_commands.extend([ + ' '.join(pipes.quote(x) for x in command_args), 'status=${?}', + 'echo "status=${status}"', 'exit ${status}' + ]) + adb_command.append('; '.join(script_commands)) + child = subprocess.Popen(adb_command, + shell=IS_WINDOWS_HOST, + stdin=open(os.devnull), + stdout=subprocess.PIPE) - 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') - if data == '': - break - if final_line is not None: - # It wasn’t really the final line. - print(final_line, end='') + FINAL_LINE_RE = re.compile('status=(\d+)$') final_line = None - if FINAL_LINE_RE.match(data.rstrip()): - final_line = data - else: - print(data, end='') + while True: + # Use readline so that the test output appears “live” when running. + data = child.stdout.readline().decode('utf-8') + if data == '': + break + if final_line is not None: + # It wasn’t really the final line. + print(final_line, end='') + final_line = None + if FINAL_LINE_RE.match(data.rstrip()): + final_line = data + else: + print(data, end='') - if final_line is None: - # Maybe there was some stderr output after the end of stdout. Old versions - # of adb, prior to when the exit status could be communicated, smush the - # two together. - raise subprocess.CalledProcessError(-1, adb_command) - status = int(FINAL_LINE_RE.match(final_line.rstrip()).group(1)) - if status != 0: - raise subprocess.CalledProcessError(status, adb_command) + if final_line is None: + # Maybe there was some stderr output after the end of stdout. Old + # versions of adb, prior to when the exit status could be + # communicated, smush the two together. + raise subprocess.CalledProcessError(-1, adb_command) + status = int(FINAL_LINE_RE.match(final_line.rstrip()).group(1)) + if status != 0: + raise subprocess.CalledProcessError(status, adb_command) - child.wait() - if child.returncode != 0: - raise subprocess.CalledProcessError(subprocess.returncode, adb_command) + child.wait() + if child.returncode != 0: + raise subprocess.CalledProcessError(subprocess.returncode, + adb_command) - # /system/bin/mktemp isn’t normally present prior to Android 6.0 (M), where - # toybox was introduced (Android platform/manifest 9a2c01e8450b). Fake it with - # a host-generated name. This won’t retry if the name is in use, but with 122 - # bits of randomness, it should be OK. This uses “mkdir” instead of “mkdir -p” - # because the latter will not indicate failure if the directory already - # exists. - device_temp_dir = '/data/local/tmp/%s.%s' % (test, uuid.uuid4().hex) - _adb_shell(['mkdir', device_temp_dir]) + # /system/bin/mktemp isn’t normally present prior to Android 6.0 (M), where + # toybox was introduced (Android platform/manifest 9a2c01e8450b). Fake it + # with a host-generated name. This won’t retry if the name is in use, but + # with 122 bits of randomness, it should be OK. This uses “mkdir” instead of + # “mkdir -p”because the latter will not indicate failure if the directory + # already exists. + device_temp_dir = '/data/local/tmp/%s.%s' % (test, uuid.uuid4().hex) + _adb_shell(['mkdir', device_temp_dir]) - try: - # Specify test dependencies that must be pushed to the device. This could be - # determined automatically in a GN build, following the example used for - # Fuchsia. Since nothing like that exists for GYP, hard-code it for - # supported tests. - test_build_artifacts = [test, 'crashpad_handler'] - test_data = ['test/test_paths_test_data_root.txt'] + try: + # Specify test dependencies that must be pushed to the device. This + # could be determined automatically in a GN build, following the example + # used for Fuchsia. Since nothing like that exists for GYP, hard-code it + # for supported tests. + test_build_artifacts = [test, 'crashpad_handler'] + test_data = ['test/test_paths_test_data_root.txt'] - if test == 'crashpad_test_test': - test_build_artifacts.append( - 'crashpad_test_test_multiprocess_exec_test_child') - elif test == 'crashpad_util_test': - test_data.append('util/net/testdata/') + if test == 'crashpad_test_test': + test_build_artifacts.append( + 'crashpad_test_test_multiprocess_exec_test_child') + elif test == 'crashpad_util_test': + test_data.append('util/net/testdata/') - # Establish the directory structure on the device. - device_out_dir = posixpath.join(device_temp_dir, 'out') - device_mkdirs = [device_out_dir] - for source_path in test_data: - # A trailing slash could reasonably mean to copy an entire directory, but - # will interfere with what’s needed from the path split. All parent - # directories of any source_path need to be be represented in - # device_mkdirs, but it’s important that no source_path itself wind up in - # device_mkdirs, even if source_path names a directory, because that would - # cause the “adb push” of the directory below to behave incorrectly. - if source_path.endswith(posixpath.sep): - source_path = source_path[:-1] + # Establish the directory structure on the device. + device_out_dir = posixpath.join(device_temp_dir, 'out') + device_mkdirs = [device_out_dir] + for source_path in test_data: + # A trailing slash could reasonably mean to copy an entire + # directory, but will interfere with what’s needed from the path + # split. All parent directories of any source_path need to be be + # represented in device_mkdirs, but it’s important that no + # source_path itself wind up in device_mkdirs, even if source_path + # names a directory, because that would cause the “adb push” of the + # directory below to behave incorrectly. + if source_path.endswith(posixpath.sep): + source_path = source_path[:-1] - device_source_path = posixpath.join(device_temp_dir, source_path) - device_mkdir = posixpath.split(device_source_path)[0] - if device_mkdir not in device_mkdirs: - device_mkdirs.append(device_mkdir) - adb_mkdir_command = ['mkdir', '-p'] - adb_mkdir_command.extend(device_mkdirs) - _adb_shell(adb_mkdir_command) + device_source_path = posixpath.join(device_temp_dir, source_path) + device_mkdir = posixpath.split(device_source_path)[0] + if device_mkdir not in device_mkdirs: + device_mkdirs.append(device_mkdir) + adb_mkdir_command = ['mkdir', '-p'] + adb_mkdir_command.extend(device_mkdirs) + _adb_shell(adb_mkdir_command) - # Push the test binary and any other build output to the device. - local_test_build_artifacts = [] - for artifact in test_build_artifacts: - local_test_build_artifacts.append(os.path.join(binary_dir, artifact)) - _adb_push(local_test_build_artifacts, device_out_dir) + # Push the test binary and any other build output to the device. + local_test_build_artifacts = [] + for artifact in test_build_artifacts: + local_test_build_artifacts.append(os.path.join( + binary_dir, artifact)) + _adb_push(local_test_build_artifacts, device_out_dir) - # Push test data to the device. - for source_path in test_data: - _adb_push([os.path.join(CRASHPAD_DIR, source_path)], - posixpath.join(device_temp_dir, source_path)) + # Push test data to the device. + for source_path in test_data: + _adb_push([os.path.join(CRASHPAD_DIR, source_path)], + posixpath.join(device_temp_dir, source_path)) - # Run the test on the device. Pass the test data root in the environment. - # - # Because the test will not run with its standard output attached to a - # pseudo-terminal device, gtest will not normally enable colored output, so - # mimic gtest’s own logic for deciding whether to enable color by checking - # this script’s own standard output connection. The whitelist of TERM values - # comes from gtest googletest/src/gtest.cc - # testing::internal::ShouldUseColor(). - env = {'CRASHPAD_TEST_DATA_ROOT': device_temp_dir} - gtest_color = os.environ.get('GTEST_COLOR') - if gtest_color in ('auto', None): - if (sys.stdout.isatty() and - (os.environ.get('TERM') in - ('xterm', 'xterm-color', 'xterm-256color', 'screen', - 'screen-256color', 'tmux', 'tmux-256color', 'rxvt-unicode', - 'rxvt-unicode-256color', 'linux', 'cygwin') or - (IS_WINDOWS_HOST and _EnableVTProcessingOnWindowsConsole()))): - gtest_color = 'yes' - else: - gtest_color = 'no' - env['GTEST_COLOR'] = gtest_color - _adb_shell([posixpath.join(device_out_dir, test)] + extra_command_line, env) - finally: - _adb_shell(['rm', '-rf', device_temp_dir]) + # Run the test on the device. Pass the test data root in the + # environment. + # + # Because the test will not run with its standard output attached to a + # pseudo-terminal device, gtest will not normally enable colored output, + # so mimic gtest’s own logic for deciding whether to enable color by + # checking this script’s own standard output connection. The whitelist + # of TERM values comes from gtest googletest/src/gtest.cc + # testing::internal::ShouldUseColor(). + env = {'CRASHPAD_TEST_DATA_ROOT': device_temp_dir} + gtest_color = os.environ.get('GTEST_COLOR') + if gtest_color in ('auto', None): + if (sys.stdout.isatty() and + (os.environ.get('TERM') + in ('xterm', 'xterm-color', 'xterm-256color', 'screen', + 'screen-256color', 'tmux', 'tmux-256color', 'rxvt-unicode', + 'rxvt-unicode-256color', 'linux', 'cygwin') or + (IS_WINDOWS_HOST and _EnableVTProcessingOnWindowsConsole()))): + gtest_color = 'yes' + else: + gtest_color = 'no' + env['GTEST_COLOR'] = gtest_color + _adb_shell([posixpath.join(device_out_dir, test)] + extra_command_line, + env) + finally: + _adb_shell(['rm', '-rf', device_temp_dir]) def _GetFuchsiaSDKRoot(): - arch = 'mac-amd64' if sys.platform == 'darwin' else 'linux-amd64' - return os.path.join(CRASHPAD_DIR, 'third_party', 'fuchsia', 'sdk', arch) + arch = 'mac-amd64' if sys.platform == 'darwin' else 'linux-amd64' + return os.path.join(CRASHPAD_DIR, 'third_party', 'fuchsia', 'sdk', arch) def _GenerateFuchsiaRuntimeDepsFiles(binary_dir, tests): - """Ensures a <binary_dir>/<test>.runtime_deps file exists for each test.""" - targets_file = os.path.join(binary_dir, 'targets.txt') - with open(targets_file, 'wb') as f: - f.write('//:' + '\n//:'.join(tests) + '\n') - gn_path = _FindGNFromBinaryDir(binary_dir) - subprocess.check_call( - [gn_path, '--root=' + CRASHPAD_DIR, 'gen', binary_dir, - '--runtime-deps-list-file=' + targets_file]) + """Ensures a <binary_dir>/<test>.runtime_deps file exists for each test.""" + targets_file = os.path.join(binary_dir, 'targets.txt') + with open(targets_file, 'wb') as f: + f.write('//:' + '\n//:'.join(tests) + '\n') + gn_path = _FindGNFromBinaryDir(binary_dir) + subprocess.check_call([ + gn_path, '--root=' + CRASHPAD_DIR, 'gen', binary_dir, + '--runtime-deps-list-file=' + targets_file + ]) - # Run again so that --runtime-deps-list-file isn't in the regen rule. See - # https://crbug.com/814816. - subprocess.check_call( - [gn_path, '--root=' + CRASHPAD_DIR, 'gen', binary_dir]) + # Run again so that --runtime-deps-list-file isn't in the regen rule. See + # https://crbug.com/814816. + subprocess.check_call( + [gn_path, '--root=' + CRASHPAD_DIR, 'gen', binary_dir]) def _HandleOutputFromFuchsiaLogListener(process, done_message): - """Pass through the output from |process| (which should be an instance of - Fuchsia's loglistener) until a special termination |done_message| is - encountered. + """Pass through the output from |process| (which should be an instance of + Fuchsia's loglistener) until a special termination |done_message| is + encountered. - Also attempts to determine if any tests failed by inspecting the log output, - and returns False if there were failures. - """ - success = True - while True: - line = process.stdout.readline().rstrip() - if 'FAILED TEST' in line: - success = False - elif done_message in line and 'echo ' not in line: - break - print(line) - return success + Also attempts to determine if any tests failed by inspecting the log output, + and returns False if there were failures. + """ + success = True + while True: + line = process.stdout.readline().rstrip() + if 'FAILED TEST' in line: + success = False + elif done_message in line and 'echo ' not in line: + break + print(line) + return success def _RunOnFuchsiaTarget(binary_dir, test, device_name, extra_command_line): - """Runs the given Fuchsia |test| executable on the given |device_name|. The - device must already be booted. + """Runs the given Fuchsia |test| executable on the given |device_name|. The + device must already be booted. - Copies the executable and its runtime dependencies as specified by GN to the - target in /tmp using `netcp`, runs the binary on the target, and logs output - back to stdout on this machine via `loglistener`. - """ - sdk_root = _GetFuchsiaSDKRoot() - - # Run loglistener and filter the output to know when the test is done. - loglistener_process = subprocess.Popen( - [os.path.join(sdk_root, 'tools', 'loglistener'), device_name], - stdout=subprocess.PIPE, stdin=open(os.devnull), stderr=open(os.devnull)) - - runtime_deps_file = os.path.join(binary_dir, test + '.runtime_deps') - with open(runtime_deps_file, 'rb') as f: - runtime_deps = f.read().splitlines() - - def netruncmd(*args): - """Runs a list of commands on the target device. Each command is escaped - by using pipes.quote(), and then each command is chained by shell ';'. + Copies the executable and its runtime dependencies as specified by GN to the + target in /tmp using `netcp`, runs the binary on the target, and logs output + back to stdout on this machine via `loglistener`. """ - netruncmd_path = os.path.join(sdk_root, 'tools', 'netruncmd') - final_args = ' ; '.join(' '.join(pipes.quote(x) for x in command) - for command in args) - subprocess.check_call([netruncmd_path, device_name, final_args]) + sdk_root = _GetFuchsiaSDKRoot() - try: - unique_id = uuid.uuid4().hex - test_root = '/tmp/%s_%s' % (test, unique_id) - tmp_root = test_root + '/tmp' - staging_root = test_root + '/pkg' + # Run loglistener and filter the output to know when the test is done. + loglistener_process = subprocess.Popen( + [os.path.join(sdk_root, 'tools', 'loglistener'), device_name], + stdout=subprocess.PIPE, + stdin=open(os.devnull), + stderr=open(os.devnull)) - # Make a staging directory tree on the target. - directories_to_create = [tmp_root, - '%s/bin' % staging_root, - '%s/assets' % staging_root] - netruncmd(['mkdir', '-p'] + directories_to_create) + runtime_deps_file = os.path.join(binary_dir, test + '.runtime_deps') + with open(runtime_deps_file, 'rb') as f: + runtime_deps = f.read().splitlines() - def netcp(local_path): - """Uses `netcp` to copy a file or directory to the device. Files located - inside the build dir are stored to /pkg/bin, otherwise to /pkg/assets. - .so files are stored somewhere completely different, into /boot/lib (!). - This is because the loader service does not yet correctly handle the - namespace in which the caller is being run, and so can only load .so files - from a couple hardcoded locations, the only writable one of which is - /boot/lib, so we copy all .so files there. This bug is filed upstream as - ZX-1619. - """ - in_binary_dir = local_path.startswith(binary_dir + '/') - if in_binary_dir: - if local_path.endswith('.so'): - target_path = os.path.join( - '/boot/lib', local_path[len(binary_dir)+1:]) - else: - target_path = os.path.join( - staging_root, 'bin', local_path[len(binary_dir)+1:]) - else: - relative_path = os.path.relpath(local_path, CRASHPAD_DIR) - target_path = os.path.join(staging_root, 'assets', relative_path) - netcp_path = os.path.join(sdk_root, 'tools', 'netcp') - subprocess.check_call([netcp_path, local_path, - device_name + ':' + target_path], - stderr=open(os.devnull)) + def netruncmd(*args): + """Runs a list of commands on the target device. Each command is escaped + by using pipes.quote(), and then each command is chained by shell ';'. + """ + netruncmd_path = os.path.join(sdk_root, 'tools', 'netruncmd') + final_args = ' ; '.join( + ' '.join(pipes.quote(x) for x in command) for command in args) + subprocess.check_call([netruncmd_path, device_name, final_args]) - # Copy runtime deps into the staging tree. - for dep in runtime_deps: - local_path = os.path.normpath(os.path.join(binary_dir, dep)) - if os.path.isdir(local_path): - for root, dirs, files in os.walk(local_path): - for f in files: - netcp(os.path.join(root, f)) - else: - netcp(local_path) + try: + unique_id = uuid.uuid4().hex + test_root = '/tmp/%s_%s' % (test, unique_id) + tmp_root = test_root + '/tmp' + staging_root = test_root + '/pkg' - done_message = 'TERMINATED: ' + unique_id - namespace_command = [ - 'namespace', '/pkg=' + staging_root, '/tmp=' + tmp_root, '/svc=/svc', - '--replace-child-argv0=/pkg/bin/' + test, '--', - staging_root + '/bin/' + test] + extra_command_line - netruncmd(namespace_command, ['echo', done_message]) + # Make a staging directory tree on the target. + directories_to_create = [ + tmp_root, + '%s/bin' % staging_root, + '%s/assets' % staging_root + ] + netruncmd(['mkdir', '-p'] + directories_to_create) - success = _HandleOutputFromFuchsiaLogListener( - loglistener_process, done_message) - if not success: - raise subprocess.CalledProcessError(1, test) - finally: - netruncmd(['rm', '-rf', test_root]) + def netcp(local_path): + """Uses `netcp` to copy a file or directory to the device. Files + located inside the build dir are stored to /pkg/bin, otherwise to + /pkg/assets. .so files are stored somewhere completely different, + into /boot/lib (!). This is because the loader service does not yet + correctly handle the namespace in which the caller is being run, and + so can only load .so files from a couple hardcoded locations, the + only writable one of which is /boot/lib, so we copy all .so files + there. This bug is filed upstream as ZX-1619. + """ + in_binary_dir = local_path.startswith(binary_dir + '/') + if in_binary_dir: + if local_path.endswith('.so'): + target_path = os.path.join('/boot/lib', + local_path[len(binary_dir) + 1:]) + else: + target_path = os.path.join(staging_root, 'bin', + local_path[len(binary_dir) + 1:]) + else: + relative_path = os.path.relpath(local_path, CRASHPAD_DIR) + target_path = os.path.join(staging_root, 'assets', + relative_path) + netcp_path = os.path.join(sdk_root, 'tools', 'netcp') + subprocess.check_call( + [netcp_path, local_path, device_name + ':' + target_path], + stderr=open(os.devnull)) + + # Copy runtime deps into the staging tree. + for dep in runtime_deps: + local_path = os.path.normpath(os.path.join(binary_dir, dep)) + if os.path.isdir(local_path): + for root, dirs, files in os.walk(local_path): + for f in files: + netcp(os.path.join(root, f)) + else: + netcp(local_path) + + done_message = 'TERMINATED: ' + unique_id + namespace_command = [ + 'namespace', '/pkg=' + staging_root, '/tmp=' + tmp_root, + '/svc=/svc', '--replace-child-argv0=/pkg/bin/' + test, '--', + staging_root + '/bin/' + test + ] + extra_command_line + netruncmd(namespace_command, ['echo', done_message]) + + success = _HandleOutputFromFuchsiaLogListener(loglistener_process, + done_message) + if not success: + raise subprocess.CalledProcessError(1, test) + finally: + netruncmd(['rm', '-rf', test_root]) def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False): - """Runs the given iOS |test| app on iPhone 8 with the default OS version.""" + """Runs the given iOS |test| app on iPhone 8 with the default OS version.""" - def xctest(binary_dir, test): - """Returns a dict containing the xctestrun data needed to run an - XCTest-based test app.""" - test_path = os.path.join(CRASHPAD_DIR, binary_dir) - module_data = { - 'TestBundlePath': os.path.join(test_path, test + '_module.xctest'), - 'TestHostPath': os.path.join(test_path, test + '.app'), - 'TestingEnvironmentVariables': { - 'DYLD_FRAMEWORK_PATH': '__TESTROOT__/Debug-iphonesimulator:', - 'DYLD_INSERT_LIBRARIES': ( - '__PLATFORMS__/iPhoneSimulator.platform/Developer/' - 'usr/lib/libXCTestBundleInject.dylib'), - 'DYLD_LIBRARY_PATH': '__TESTROOT__/Debug-iphonesimulator', - 'IDEiPhoneInternalTestBundleName': test + '.app', - 'XCInjectBundleInto': '__TESTHOST__/' + test, - } - } - return { test: module_data } + def xctest(binary_dir, test): + """Returns a dict containing the xctestrun data needed to run an + XCTest-based test app.""" + test_path = os.path.join(CRASHPAD_DIR, binary_dir) + module_data = { + 'TestBundlePath': os.path.join(test_path, test + '_module.xctest'), + 'TestHostPath': os.path.join(test_path, test + '.app'), + 'TestingEnvironmentVariables': { + 'DYLD_FRAMEWORK_PATH': '__TESTROOT__/Debug-iphonesimulator:', + 'DYLD_INSERT_LIBRARIES': + ('__PLATFORMS__/iPhoneSimulator.platform/Developer/' + 'usr/lib/libXCTestBundleInject.dylib'), + 'DYLD_LIBRARY_PATH': '__TESTROOT__/Debug-iphonesimulator', + 'IDEiPhoneInternalTestBundleName': test + '.app', + 'XCInjectBundleInto': '__TESTHOST__/' + test, + } + } + return {test: module_data} - def xcuitest(binary_dir, test): - """Returns a dict containing the xctestrun data needed to run an - XCUITest-based test app.""" + def xcuitest(binary_dir, test): + """Returns a dict containing the xctestrun data needed to run an + XCUITest-based test app.""" - test_path = os.path.join(CRASHPAD_DIR, binary_dir) - runner_path = os.path.join(test_path, test + '_module-Runner.app') - bundle_path = os.path.join(runner_path, 'PlugIns', test + '_module.xctest') - target_app_path = os.path.join(test_path, test + '.app') - module_data = { - 'IsUITestBundle': True, - 'IsXCTRunnerHostedTestBundle': True, - 'TestBundlePath': bundle_path, - 'TestHostPath': runner_path, - 'UITargetAppPath': target_app_path, - 'DependentProductPaths': [ bundle_path, runner_path, target_app_path ], - 'TestingEnvironmentVariables': { - 'DYLD_FRAMEWORK_PATH': '__TESTROOT__/Debug-iphonesimulator:', - 'DYLD_INSERT_LIBRARIES': ( - '__PLATFORMS__/iPhoneSimulator.platform/Developer/' - 'usr/lib/libXCTestBundleInject.dylib'), - 'DYLD_LIBRARY_PATH': '__TESTROOT__/Debug-iphonesimulator', - 'XCInjectBundleInto': '__TESTHOST__/' + test + '_module-Runner', - }, - } - return { test: module_data } + test_path = os.path.join(CRASHPAD_DIR, binary_dir) + runner_path = os.path.join(test_path, test + '_module-Runner.app') + bundle_path = os.path.join(runner_path, 'PlugIns', + test + '_module.xctest') + target_app_path = os.path.join(test_path, test + '.app') + module_data = { + 'IsUITestBundle': True, + 'IsXCTRunnerHostedTestBundle': True, + 'TestBundlePath': bundle_path, + 'TestHostPath': runner_path, + 'UITargetAppPath': target_app_path, + 'DependentProductPaths': [ + bundle_path, runner_path, target_app_path + ], + 'TestingEnvironmentVariables': { + 'DYLD_FRAMEWORK_PATH': '__TESTROOT__/Debug-iphonesimulator:', + 'DYLD_INSERT_LIBRARIES': + ('__PLATFORMS__/iPhoneSimulator.platform/Developer/' + 'usr/lib/libXCTestBundleInject.dylib'), + 'DYLD_LIBRARY_PATH': '__TESTROOT__/Debug-iphonesimulator', + 'XCInjectBundleInto': '__TESTHOST__/' + test + '_module-Runner', + }, + } + return {test: module_data} - with tempfile.NamedTemporaryFile() as f: - import plistlib + with tempfile.NamedTemporaryFile() as f: + import plistlib - 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) + 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) + + subprocess.check_call([ + 'xcodebuild', 'test-without-building', '-xctestrun', xctestrun_path, + '-destination', 'platform=iOS Simulator,name=iPhone 8' + ]) - subprocess.check_call(['xcodebuild', 'test-without-building', - '-xctestrun', xctestrun_path, '-destination', - 'platform=iOS Simulator,name=iPhone 8']) # This script is primarily used from the waterfall so that the list of tests # that are run is maintained in-tree, rather than in a separate infrastructure # location in the recipe. def main(args): - parser = argparse.ArgumentParser(description='Run Crashpad unittests.') - parser.add_argument('binary_dir', help='Root of build dir') - parser.add_argument('test', nargs='*', help='Specific test(s) to run.') - parser.add_argument('--gtest_filter', - help='GTest filter applied to GTest binary runs.') - args = parser.parse_args() + parser = argparse.ArgumentParser(description='Run Crashpad unittests.') + parser.add_argument('binary_dir', help='Root of build dir') + parser.add_argument('test', nargs='*', help='Specific test(s) to run.') + parser.add_argument('--gtest_filter', + help='GTest filter applied to GTest binary runs.') + args = parser.parse_args() - # Tell 64-bit Windows tests where to find 32-bit test executables, for - # cross-bitted testing. This relies on the fact that the GYP build by default - # uses {Debug,Release} for the 32-bit build and {Debug,Release}_x64 for the - # 64-bit build. This is not a universally valid assumption, and if it’s not - # met, 64-bit tests that require 32-bit build output will disable themselves - # dynamically. - if (sys.platform == 'win32' and args.binary_dir.endswith('_x64') and - 'CRASHPAD_TEST_32_BIT_OUTPUT' not in os.environ): - binary_dir_32 = args.binary_dir[:-4] - if os.path.isdir(binary_dir_32): - os.environ['CRASHPAD_TEST_32_BIT_OUTPUT'] = binary_dir_32 + # Tell 64-bit Windows tests where to find 32-bit test executables, for + # cross-bitted testing. This relies on the fact that the GYP build by + # default uses {Debug,Release} for the 32-bit build and {Debug,Release}_x64 + # for the 64-bit build. This is not a universally valid assumption, and if + # it’s not met, 64-bit tests that require 32-bit build output will disable + # themselves dynamically. + if (sys.platform == 'win32' and args.binary_dir.endswith('_x64') and + 'CRASHPAD_TEST_32_BIT_OUTPUT' not in os.environ): + binary_dir_32 = args.binary_dir[:-4] + if os.path.isdir(binary_dir_32): + os.environ['CRASHPAD_TEST_32_BIT_OUTPUT'] = binary_dir_32 - target_os = _BinaryDirTargetOS(args.binary_dir) - is_android = target_os == 'android' - is_fuchsia = target_os == 'fuchsia' - is_ios = target_os == 'ios' + target_os = _BinaryDirTargetOS(args.binary_dir) + is_android = target_os == 'android' + is_fuchsia = target_os == 'fuchsia' + is_ios = target_os == 'ios' - tests = [ - 'crashpad_client_test', - 'crashpad_handler_test', - 'crashpad_minidump_test', - 'crashpad_snapshot_test', - 'crashpad_test_test', - 'crashpad_util_test', - ] + tests = [ + 'crashpad_client_test', + 'crashpad_handler_test', + 'crashpad_minidump_test', + 'crashpad_snapshot_test', + 'crashpad_test_test', + 'crashpad_util_test', + ] - if is_android: - android_device = os.environ.get('ANDROID_DEVICE') - if not android_device: - adb_devices = subprocess.check_output(['adb', 'devices'], - shell=IS_WINDOWS_HOST) - devices = [] - for line in adb_devices.splitlines(): - line = line.decode('utf-8') - if (line == 'List of devices attached' or - re.match('^\* daemon .+ \*$', line) or - line == ''): - continue - (device, ignore) = line.split('\t') - devices.append(device) - if len(devices) != 1: - print("Please set ANDROID_DEVICE to your device's id", file=sys.stderr) - return 2 - android_device = devices[0] - print('Using autodetected Android device:', android_device) - elif is_fuchsia: - zircon_nodename = os.environ.get('ZIRCON_NODENAME') - if not zircon_nodename: - netls = os.path.join(_GetFuchsiaSDKRoot(), 'tools', 'netls') - popen = subprocess.Popen([netls, '--nowait'], stdout=subprocess.PIPE) - devices = popen.communicate()[0].splitlines() - if popen.returncode != 0 or len(devices) != 1: - print("Please set ZIRCON_NODENAME to your device's hostname", - file=sys.stderr) - return 2 - zircon_nodename = devices[0].strip().split()[1] - print('Using autodetected Fuchsia device:', zircon_nodename) - _GenerateFuchsiaRuntimeDepsFiles( - args.binary_dir, [t for t in tests if not t.endswith('.py')]) - elif is_ios: - tests.append('ios_crash_xcuitests') - elif IS_WINDOWS_HOST: - tests.append('snapshot/win/end_to_end_test.py') + if is_android: + android_device = os.environ.get('ANDROID_DEVICE') + if not android_device: + adb_devices = subprocess.check_output(['adb', 'devices'], + shell=IS_WINDOWS_HOST) + devices = [] + for line in adb_devices.splitlines(): + line = line.decode('utf-8') + if (line == 'List of devices attached' or + re.match('^\* daemon .+ \*$', line) or line == ''): + continue + (device, ignore) = line.split('\t') + devices.append(device) + if len(devices) != 1: + print("Please set ANDROID_DEVICE to your device's id", + file=sys.stderr) + return 2 + android_device = devices[0] + print('Using autodetected Android device:', android_device) + elif is_fuchsia: + zircon_nodename = os.environ.get('ZIRCON_NODENAME') + if not zircon_nodename: + netls = os.path.join(_GetFuchsiaSDKRoot(), 'tools', 'netls') + popen = subprocess.Popen([netls, '--nowait'], + stdout=subprocess.PIPE) + devices = popen.communicate()[0].splitlines() + if popen.returncode != 0 or len(devices) != 1: + print("Please set ZIRCON_NODENAME to your device's hostname", + file=sys.stderr) + return 2 + zircon_nodename = devices[0].strip().split()[1] + print('Using autodetected Fuchsia device:', zircon_nodename) + _GenerateFuchsiaRuntimeDepsFiles( + args.binary_dir, [t for t in tests if not t.endswith('.py')]) + elif is_ios: + tests.append('ios_crash_xcuitests') + elif IS_WINDOWS_HOST: + tests.append('snapshot/win/end_to_end_test.py') - if args.test: - for t in args.test: - if t not in tests: - print('Unrecognized test:', t, file=sys.stderr) - return 3 - tests = args.test + if args.test: + for t in args.test: + if t not in tests: + print('Unrecognized test:', t, file=sys.stderr) + return 3 + tests = args.test - for test in tests: - print('-' * 80) - print(test) - print('-' * 80) - if test.endswith('.py'): - subprocess.check_call( - [sys.executable, os.path.join(CRASHPAD_DIR, test), args.binary_dir]) - else: - extra_command_line = [] - if args.gtest_filter: - extra_command_line.append('--gtest_filter=' + args.gtest_filter) - if is_android: - _RunOnAndroidTarget(args.binary_dir, test, android_device, - extra_command_line) - elif is_fuchsia: - _RunOnFuchsiaTarget(args.binary_dir, test, zircon_nodename, - extra_command_line) - elif is_ios: - _RunOnIOSTarget(args.binary_dir, test, - is_xcuitest=test.startswith('ios')) - else: - subprocess.check_call([os.path.join(args.binary_dir, test)] + - extra_command_line) + for test in tests: + print('-' * 80) + print(test) + print('-' * 80) + if test.endswith('.py'): + subprocess.check_call([ + sys.executable, + os.path.join(CRASHPAD_DIR, test), args.binary_dir + ]) + else: + extra_command_line = [] + if args.gtest_filter: + extra_command_line.append('--gtest_filter=' + args.gtest_filter) + if is_android: + _RunOnAndroidTarget(args.binary_dir, test, android_device, + extra_command_line) + elif is_fuchsia: + _RunOnFuchsiaTarget(args.binary_dir, test, zircon_nodename, + extra_command_line) + elif is_ios: + _RunOnIOSTarget(args.binary_dir, + test, + is_xcuitest=test.startswith('ios')) + else: + subprocess.check_call([os.path.join(args.binary_dir, test)] + + extra_command_line) - return 0 + return 0 if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + sys.exit(main(sys.argv[1:])) diff --git a/doc/support/generate_doxygen.py b/doc/support/generate_doxygen.py index a93028df..577b51e5 100755 --- a/doc/support/generate_doxygen.py +++ b/doc/support/generate_doxygen.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# coding: utf-8 # Copyright 2017 The Crashpad Authors. All rights reserved. # @@ -24,26 +23,26 @@ import sys def main(args): - script_dir = os.path.dirname(__file__) - crashpad_dir = os.path.join(script_dir, os.pardir, os.pardir) + script_dir = os.path.dirname(__file__) + crashpad_dir = os.path.join(script_dir, os.pardir, os.pardir) - # Run from the Crashpad project root directory. - os.chdir(crashpad_dir) + # Run from the Crashpad project root directory. + os.chdir(crashpad_dir) - output_dir = os.path.join('out', 'doc', 'doxygen') + output_dir = os.path.join('out', 'doc', 'doxygen') - if os.path.isdir(output_dir) and not os.path.islink(output_dir): - shutil.rmtree(output_dir) - elif os.path.exists(output_dir): - os.unlink(output_dir) + if os.path.isdir(output_dir) and not os.path.islink(output_dir): + shutil.rmtree(output_dir) + elif os.path.exists(output_dir): + os.unlink(output_dir) - os.makedirs(output_dir, 0o755) + os.makedirs(output_dir, 0o755) - doxy_file = os.path.join('doc', 'support', 'crashpad.doxy') - subprocess.check_call(['doxygen', doxy_file]) + doxy_file = os.path.join('doc', 'support', 'crashpad.doxy') + subprocess.check_call(['doxygen', doxy_file]) - return 0 + return 0 if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + sys.exit(main(sys.argv[1:])) diff --git a/infra/config/PRESUBMIT.py b/infra/config/PRESUBMIT.py index c2317e1b..ca044332 100644 --- a/infra/config/PRESUBMIT.py +++ b/infra/config/PRESUBMIT.py @@ -12,8 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. + def CheckChangeOnUpload(input_api, output_api): - return input_api.canned_checks.CheckChangedLUCIConfigs(input_api, output_api) + return input_api.canned_checks.CheckChangedLUCIConfigs( + input_api, output_api) + def CheckChangeOnCommit(input_api, output_api): - return input_api.canned_checks.CheckChangedLUCIConfigs(input_api, output_api) + return input_api.canned_checks.CheckChangedLUCIConfigs( + input_api, output_api) diff --git a/snapshot/win/end_to_end_test.py b/snapshot/win/end_to_end_test.py index 8823785f..b1919ade 100755 --- a/snapshot/win/end_to_end_test.py +++ b/snapshot/win/end_to_end_test.py @@ -29,462 +29,452 @@ import win32con import win32pipe import winerror - g_temp_dirs = [] g_had_failures = False def MakeTempDir(): - global g_temp_dirs - new_dir = tempfile.mkdtemp() - g_temp_dirs.append(new_dir) - return new_dir + global g_temp_dirs + new_dir = tempfile.mkdtemp() + g_temp_dirs.append(new_dir) + return new_dir def CleanUpTempDirs(): - global g_temp_dirs - for d in g_temp_dirs: - subprocess.call(['rmdir', '/s', '/q', d], shell=True) + global g_temp_dirs + for d in g_temp_dirs: + subprocess.call(['rmdir', '/s', '/q', d], shell=True) def FindInstalledWindowsApplication(app_path): - search_paths = [os.getenv('PROGRAMFILES(X86)'), - os.getenv('PROGRAMFILES'), - os.getenv('PROGRAMW6432'), - os.getenv('LOCALAPPDATA')] - search_paths += os.getenv('PATH', '').split(os.pathsep) + search_paths = [ + os.getenv('PROGRAMFILES(X86)'), + os.getenv('PROGRAMFILES'), + os.getenv('PROGRAMW6432'), + os.getenv('LOCALAPPDATA') + ] + search_paths += os.getenv('PATH', '').split(os.pathsep) - for search_path in search_paths: - if not search_path: - continue - path = os.path.join(search_path, app_path) - if os.path.isfile(path): - return path + for search_path in search_paths: + if not search_path: + continue + path = os.path.join(search_path, app_path) + if os.path.isfile(path): + return path - return None - - -def GetCdbPath(): - """Search in some reasonable places to find cdb.exe. Searches x64 before x86 - and newer versions before older versions. - """ - possible_paths = ( - os.path.join('Windows Kits', '10', 'Debuggers', 'x64'), - os.path.join('Windows Kits', '10', 'Debuggers', 'x86'), - os.path.join('Windows Kits', '8.1', 'Debuggers', 'x64'), - os.path.join('Windows Kits', '8.1', 'Debuggers', 'x86'), - os.path.join('Windows Kits', '8.0', 'Debuggers', 'x64'), - os.path.join('Windows Kits', '8.0', 'Debuggers', 'x86'), - 'Debugging Tools For Windows (x64)', - 'Debugging Tools For Windows (x86)', - 'Debugging Tools For Windows',) - for possible_path in possible_paths: - app_path = os.path.join(possible_path, 'cdb.exe') - app_path = FindInstalledWindowsApplication(app_path) - if app_path: - return app_path - return None - - -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. - - This is used as a drop-in replacement for os.path.exists() and os.access() to - test for the pipe's existence. Both of those calls tickle the pipe in a way - that appears to the server to be a client connecting, triggering error - messages when no data is received. - - Although this function only needs to test pipe existence (waiting for - CreateNamedPipe()), it actually winds up testing pipe readiness - (waiting for ConnectNamedPipe()). This is unnecessary but harmless. - """ - try: - win32pipe.WaitNamedPipe(pipe_name, win32pipe.NMPWAIT_WAIT_FOREVER) - except pywintypes.error as e: - if e[0] == winerror.ERROR_FILE_NOT_FOUND: - return False - raise - return True - - -def GetDumpFromProgram( - out_dir, pipe_name, executable_name, expect_exit_code, *args): - """Initialize a crash database, and run |executable_name| connecting to a - crash handler. If pipe_name is set, crashpad_handler will be started first. If - pipe_name is empty, the executable is responsible for starting - crashpad_handler. *args will be passed after other arguments to - executable_name. If the child process does not exit with |expect_exit_code|, - an exception will be raised. Returns the path to the minidump generated by - crashpad_handler for further testing. - """ - test_database = MakeTempDir() - handler = None - - try: - subprocess.check_call( - [os.path.join(out_dir, 'crashpad_database_util.exe'), '--create', - '--database=' + test_database]) - - if pipe_name is not None: - handler = subprocess.Popen([ - os.path.join(out_dir, 'crashpad_handler.com'), - '--pipe-name=' + pipe_name, - '--database=' + test_database - ]) - - # Wait until the server is ready. - printed = False - while not NamedPipeExistsAndReady(pipe_name): - if not printed: - print('Waiting for crashpad_handler to be ready...') - printed = True - time.sleep(0.001) - - command = [os.path.join(out_dir, executable_name), pipe_name] + list(args) - else: - command = ([os.path.join(out_dir, executable_name), - os.path.join(out_dir, 'crashpad_handler.com'), - test_database] + - list(args)) - print('Running %s' % os.path.basename(command[0])) - exit_code = subprocess.call(command) - if exit_code != expect_exit_code: - raise subprocess.CalledProcessError(exit_code, executable_name) - - out = subprocess.check_output([ - os.path.join(out_dir, 'crashpad_database_util.exe'), - '--database=' + test_database, - '--show-pending-reports', - '--show-all-report-info', - ]) - for line in out.splitlines(): - if line.strip().startswith('Path:'): - return line.partition(':')[2].strip() - finally: - if handler: - handler.kill() - - -def GetDumpFromCrashyProgram(out_dir, pipe_name): - return GetDumpFromProgram(out_dir, - pipe_name, - 'crashy_program.exe', - win32con.EXCEPTION_ACCESS_VIOLATION) - - -def GetDumpFromOtherProgram(out_dir, pipe_name, *args): - return GetDumpFromProgram( - out_dir, pipe_name, 'crash_other_program.exe', 0, *args) - - -def GetDumpFromSignal(out_dir, pipe_name, *args): - STATUS_FATAL_APP_EXIT = 0x40000015 # Not known by win32con. - return GetDumpFromProgram(out_dir, - pipe_name, - 'crashy_signal.exe', - STATUS_FATAL_APP_EXIT, - *args) - - -def GetDumpFromSelfDestroyingProgram(out_dir, pipe_name): - return GetDumpFromProgram(out_dir, - pipe_name, - 'self_destroying_program.exe', - win32con.EXCEPTION_BREAKPOINT) - - -def GetDumpFromZ7Program(out_dir, pipe_name): - return GetDumpFromProgram(out_dir, - pipe_name, - 'crashy_z7_loader.exe', - win32con.EXCEPTION_ACCESS_VIOLATION) - - -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 - expected output. - """ - - 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' - ]) - - def Check(self, pattern, message, re_flags=0): - match_obj = re.search(pattern, self.out, re_flags) - if match_obj: - # Matched. Consume up to end of match. - self.out = self.out[match_obj.end(0):] - 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) - print('-' * 80, file=sys.stderr) - print('remaining output was:\n %s' % self.out, file=sys.stderr) - print('-' * 80, file=sys.stderr) - sys.stderr.flush() - global g_had_failures - g_had_failures = True - - def Find(self, pattern, re_flags=0): - match_obj = re.search(pattern, self.out, re_flags) - if match_obj: - # Matched. Consume up to end of match. - self.out = self.out[match_obj.end(0):] - return match_obj return None -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): - """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. - """ - out = CdbRun(cdb_path, dump_path, '.ecxr') - out.Check('This dump file has an exception of interest stored in it', - 'captured exception') +def GetCdbPath(): + """Search in some reasonable places to find cdb.exe. Searches x64 before x86 + and newer versions before older versions. + """ + possible_paths = ( + os.path.join('Windows Kits', '10', 'Debuggers', 'x64'), + os.path.join('Windows Kits', '10', 'Debuggers', 'x86'), + os.path.join('Windows Kits', '8.1', 'Debuggers', 'x64'), + os.path.join('Windows Kits', '8.1', 'Debuggers', 'x86'), + os.path.join('Windows Kits', '8.0', 'Debuggers', 'x64'), + os.path.join('Windows Kits', '8.0', 'Debuggers', 'x86'), + 'Debugging Tools For Windows (x64)', + 'Debugging Tools For Windows (x86)', + 'Debugging Tools For Windows', + ) + for possible_path in possible_paths: + app_path = os.path.join(possible_path, 'cdb.exe') + app_path = FindInstalledWindowsApplication(app_path) + if app_path: + return app_path + return None - # When SomeCrashyFunction is inlined, cdb doesn't demangle its namespace as - # "`anonymous namespace'" and instead gives the decorated form. - out.Check('crashy_program!crashpad::(`anonymous namespace\'|\?A0x[0-9a-f]+)::' - 'SomeCrashyFunction', - 'exception at correct location') - out = CdbRun(cdb_path, start_handler_dump_path, '.ecxr') - out.Check('This dump file has an exception of interest stored in it', - 'captured exception (using StartHandler())') - out.Check('crashy_program!crashpad::(`anonymous namespace\'|\?A0x[0-9a-f]+)::' - 'SomeCrashyFunction', - 'exception at correct location (using StartHandler())') +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. - out = CdbRun(cdb_path, dump_path, '!peb') - out.Check(r'PEB at', 'found the PEB') - out.Check(r'Ldr\.InMemoryOrderModuleList:.*\d+ \. \d+', 'PEB_LDR_DATA saved') - out.Check(r'Base TimeStamp Module', 'module list present') - pipe_name_escaped = pipe_name.replace('\\', '\\\\') - out.Check(r'CommandLine: *\'.*crashy_program\.exe *' + pipe_name_escaped, - 'some PEB data is correct') - out.Check(r'SystemRoot=C:\\Windows', 'some of environment captured', - re.IGNORECASE) + This is used as a drop-in replacement for os.path.exists() and os.access() + to test for the pipe's existence. Both of those calls tickle the pipe in a + way that appears to the server to be a client connecting, triggering error + messages when no data is received. - out = CdbRun(cdb_path, dump_path, '?? @$peb->ProcessParameters') - out.Check(r' ImagePathName *: _UNICODE_STRING ".*\\crashy_program\.exe"', - 'PEB->ProcessParameters.ImagePathName string captured') - out.Check(' DesktopInfo *: ' - '_UNICODE_STRING "(?!--- memory read error at address ).*"', - 'PEB->ProcessParameters.DesktopInfo string captured') + Although this function only needs to test pipe existence (waiting for + CreateNamedPipe()), it actually winds up testing pipe readiness (waiting for + ConnectNamedPipe()). This is unnecessary but harmless. + """ + try: + win32pipe.WaitNamedPipe(pipe_name, win32pipe.NMPWAIT_WAIT_FOREVER) + except pywintypes.error as e: + if e[0] == winerror.ERROR_FILE_NOT_FOUND: + return False + raise + return True - out = CdbRun(cdb_path, dump_path, '!teb') - out.Check(r'TEB at', 'found the TEB') - out.Check(r'ExceptionList:\s+[0-9a-fA-F]+', 'some valid teb data') - out.Check(r'LastErrorValue:\s+2', 'correct LastErrorValue') - out = CdbRun(cdb_path, dump_path, '!gle') - out.Check('LastErrorValue: \(Win32\) 0x2 \(2\) - The system cannot find the ' - 'file specified.', '!gle gets last error') - out.Check('LastStatusValue: \(NTSTATUS\) 0xc000000f - {File Not Found} The ' - 'file %hs does not exist.', '!gle gets last ntstatus') +def GetDumpFromProgram(out_dir, pipe_name, executable_name, expect_exit_code, + *args): + """Initialize a crash database, and run |executable_name| connecting to a + crash handler. If pipe_name is set, crashpad_handler will be started first. + If pipe_name is empty, the executable is responsible for starting + crashpad_handler. *args will be passed after other arguments to + executable_name. If the child process does not exit with |expect_exit_code|, + an exception will be raised. Returns the path to the minidump generated by + crashpad_handler for further testing. + """ + test_database = MakeTempDir() + handler = None - if False: - # TODO(scottmg): Re-enable when we grab ntdll!RtlCriticalSectionList. - out = CdbRun(cdb_path, dump_path, '!locks') - out.Check(r'CritSec crashy_program!crashpad::`anonymous namespace\'::' - r'g_test_critical_section', 'lock was captured') - if platform.win32_ver()[0] != '7': - # We can't allocate CRITICAL_SECTIONs with .DebugInfo on Win 7. - out.Check(r'\*\*\* Locked', 'lock debug info was captured, and is locked') + try: + subprocess.check_call([ + os.path.join(out_dir, 'crashpad_database_util.exe'), '--create', + '--database=' + test_database + ]) - out = CdbRun(cdb_path, dump_path, '!handle') - out.Check(r'\d+ Handles', 'captured handles') - out.Check(r'Event\s+\d+', 'capture some event handles') - out.Check(r'File\s+\d+', 'capture some file handles') + if pipe_name is not None: + handler = subprocess.Popen([ + os.path.join(out_dir, 'crashpad_handler.com'), + '--pipe-name=' + pipe_name, '--database=' + test_database + ]) - out = CdbRun(cdb_path, dump_path, 'lm') - out.Check(r'Unloaded modules:', 'captured some unloaded modules') - out.Check(r'lz32\.dll', 'found expected unloaded module lz32') - out.Check(r'wmerror\.dll', 'found expected unloaded module wmerror') + # Wait until the server is ready. + printed = False + while not NamedPipeExistsAndReady(pipe_name): + if not printed: + print('Waiting for crashpad_handler to be ready...') + printed = True + time.sleep(0.001) - out = CdbRun(cdb_path, destroyed_dump_path, '.ecxr;!peb;k 2') - out.Check(r'Ldr\.InMemoryOrderModuleList:.*\d+ \. \d+', 'PEB_LDR_DATA saved') - out.Check(r'ntdll\.dll', 'ntdll present', re.IGNORECASE) + command = [os.path.join(out_dir, executable_name), pipe_name + ] + list(args) + else: + command = ([ + os.path.join(out_dir, executable_name), + os.path.join(out_dir, 'crashpad_handler.com'), test_database + ] + list(args)) + print('Running %s' % os.path.basename(command[0])) + exit_code = subprocess.call(command) + if exit_code != expect_exit_code: + raise subprocess.CalledProcessError(exit_code, executable_name) - # Check that there is no stack trace in the self-destroyed process. Confirm - # that the top is where we expect it (that's based only on IP), but subsequent - # stack entries will not be available. This confirms that we have a mostly - # valid dump, but that the stack was omitted. - out.Check(r'self_destroying_program!crashpad::`anonymous namespace\'::' - r'FreeOwnStackAndBreak.*\nquit:', - 'at correct location, no additional stack entries') + out = subprocess.check_output([ + os.path.join(out_dir, 'crashpad_database_util.exe'), + '--database=' + test_database, + '--show-pending-reports', + '--show-all-report-info', + ]) + for line in out.splitlines(): + if line.strip().startswith('Path:'): + return line.partition(':')[2].strip() + finally: + if handler: + handler.kill() - # Dump memory pointed to be EDI on the background suspended thread. We don't - # know the index of the thread because the system may have started other - # threads, so first do a run to extract the thread index that's suspended, and - # then another run to dump the data pointed to by EDI for that thread. - out = CdbRun(cdb_path, dump_path, '.ecxr;~') - match_obj = out.Find(r'(\d+)\s+Id: [0-9a-f.]+ Suspend: 1 Teb:') - if match_obj: - thread = match_obj.group(1) - out = CdbRun(cdb_path, dump_path, '.ecxr;~' + thread + 's;db /c14 edi') - out.Check(r'63 62 61 60 5f 5e 5d 5c-5b 5a 59 58 57 56 55 54 53 52 51 50', - 'data pointed to by registers captured') - # Move up one stack frame after jumping to the exception, and examine memory. - out = CdbRun(cdb_path, dump_path, - '.ecxr; .f+; dd /c100 poi(offset_pointer)-20') - out.Check(r'80000078 00000079 8000007a 0000007b 8000007c 0000007d 8000007e ' - r'0000007f 80000080 00000081 80000082 00000083 80000084 00000085 ' - r'80000086 00000087 80000088 00000089 8000008a 0000008b 8000008c ' - r'0000008d 8000008e 0000008f 80000090 00000091 80000092 00000093 ' - r'80000094 00000095 80000096 00000097', - 'data pointed to by stack captured') +def GetDumpFromCrashyProgram(out_dir, pipe_name): + return GetDumpFromProgram(out_dir, pipe_name, 'crashy_program.exe', + win32con.EXCEPTION_ACCESS_VIOLATION) - # Attempt to retrieve the value of g_extra_memory_pointer (by name), and then - # examine the memory at which it points. Both should have been saved. - out = CdbRun(cdb_path, dump_path, - 'dd poi(crashy_program!crashpad::g_extra_memory_pointer)+0x1f30 ' - 'L8') - out.Check(r'0000655e 0000656b 00006578 00006585', - 'extra memory range captured') - out = CdbRun(cdb_path, dump_path, '.dumpdebug') - out.Check(r'type \?\?\? \(333333\), size 00001000', - 'first user stream') - out.Check(r'type \?\?\? \(222222\), size 00000080', - 'second user stream') +def GetDumpFromOtherProgram(out_dir, pipe_name, *args): + return GetDumpFromProgram(out_dir, pipe_name, 'crash_other_program.exe', 0, + *args) - if z7_dump_path: - out = CdbRun(cdb_path, z7_dump_path, '.ecxr;lm') + +def GetDumpFromSignal(out_dir, pipe_name, *args): + STATUS_FATAL_APP_EXIT = 0x40000015 # Not known by win32con. + return GetDumpFromProgram(out_dir, pipe_name, 'crashy_signal.exe', + STATUS_FATAL_APP_EXIT, *args) + + +def GetDumpFromSelfDestroyingProgram(out_dir, pipe_name): + return GetDumpFromProgram(out_dir, pipe_name, 'self_destroying_program.exe', + win32con.EXCEPTION_BREAKPOINT) + + +def GetDumpFromZ7Program(out_dir, pipe_name): + return GetDumpFromProgram(out_dir, pipe_name, 'crashy_z7_loader.exe', + win32con.EXCEPTION_ACCESS_VIOLATION) + + +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 + expected output. + """ + + 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']) + + def Check(self, pattern, message, re_flags=0): + match_obj = re.search(pattern, self.out, re_flags) + if match_obj: + # Matched. Consume up to end of match. + self.out = self.out[match_obj.end(0):] + 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) + print('-' * 80, file=sys.stderr) + print('remaining output was:\n %s' % self.out, file=sys.stderr) + print('-' * 80, file=sys.stderr) + sys.stderr.flush() + global g_had_failures + g_had_failures = True + + def Find(self, pattern, re_flags=0): + match_obj = re.search(pattern, self.out, re_flags) + if match_obj: + # Matched. Consume up to end of match. + self.out = self.out[match_obj.end(0):] + return match_obj + return None + + +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): + """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. + """ + out = CdbRun(cdb_path, dump_path, '.ecxr') 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') + 'captured exception') - out = CdbRun(cdb_path, other_program_path, '.ecxr;k;~') - out.Check('Unknown exception - code deadbea7', - 'other program dump exception code') - out.Check('!Sleep', 'other program reasonable location') - out.Check("hanging_program!`anonymous namespace'::Thread1", - 'other program dump right thread') - count = 0 - while True: - match_obj = out.Find(r'Id.*Suspend: (\d+) ') + # When SomeCrashyFunction is inlined, cdb doesn't demangle its namespace as + # "`anonymous namespace'" and instead gives the decorated form. + out.Check( + 'crashy_program!crashpad::(`anonymous namespace\'|\?A0x[0-9a-f]+)::' + 'SomeCrashyFunction', 'exception at correct location') + + out = CdbRun(cdb_path, start_handler_dump_path, '.ecxr') + out.Check('This dump file has an exception of interest stored in it', + 'captured exception (using StartHandler())') + out.Check( + 'crashy_program!crashpad::(`anonymous namespace\'|\?A0x[0-9a-f]+)::' + 'SomeCrashyFunction', + 'exception at correct location (using StartHandler())') + + out = CdbRun(cdb_path, dump_path, '!peb') + out.Check(r'PEB at', 'found the PEB') + out.Check(r'Ldr\.InMemoryOrderModuleList:.*\d+ \. \d+', + 'PEB_LDR_DATA saved') + out.Check(r'Base TimeStamp Module', + 'module list present') + pipe_name_escaped = pipe_name.replace('\\', '\\\\') + out.Check(r'CommandLine: *\'.*crashy_program\.exe *' + pipe_name_escaped, + 'some PEB data is correct') + out.Check(r'SystemRoot=C:\\Windows', 'some of environment captured', + re.IGNORECASE) + + out = CdbRun(cdb_path, dump_path, '?? @$peb->ProcessParameters') + out.Check(r' ImagePathName *: _UNICODE_STRING ".*\\crashy_program\.exe"', + 'PEB->ProcessParameters.ImagePathName string captured') + out.Check( + ' DesktopInfo *: ' + '_UNICODE_STRING "(?!--- memory read error at address ).*"', + 'PEB->ProcessParameters.DesktopInfo string captured') + + out = CdbRun(cdb_path, dump_path, '!teb') + out.Check(r'TEB at', 'found the TEB') + out.Check(r'ExceptionList:\s+[0-9a-fA-F]+', 'some valid teb data') + out.Check(r'LastErrorValue:\s+2', 'correct LastErrorValue') + + out = CdbRun(cdb_path, dump_path, '!gle') + out.Check( + 'LastErrorValue: \(Win32\) 0x2 \(2\) - The system cannot find the ' + 'file specified.', '!gle gets last error') + out.Check( + 'LastStatusValue: \(NTSTATUS\) 0xc000000f - {File Not Found} The ' + 'file %hs does not exist.', '!gle gets last ntstatus') + + if False: + # TODO(scottmg): Re-enable when we grab ntdll!RtlCriticalSectionList. + out = CdbRun(cdb_path, dump_path, '!locks') + out.Check( + r'CritSec crashy_program!crashpad::`anonymous namespace\'::' + r'g_test_critical_section', 'lock was captured') + if platform.win32_ver()[0] != '7': + # We can't allocate CRITICAL_SECTIONs with .DebugInfo on Win 7. + out.Check(r'\*\*\* Locked', + 'lock debug info was captured, and is locked') + + out = CdbRun(cdb_path, dump_path, '!handle') + out.Check(r'\d+ Handles', 'captured handles') + out.Check(r'Event\s+\d+', 'capture some event handles') + out.Check(r'File\s+\d+', 'capture some file handles') + + out = CdbRun(cdb_path, dump_path, 'lm') + out.Check(r'Unloaded modules:', 'captured some unloaded modules') + out.Check(r'lz32\.dll', 'found expected unloaded module lz32') + out.Check(r'wmerror\.dll', 'found expected unloaded module wmerror') + + out = CdbRun(cdb_path, destroyed_dump_path, '.ecxr;!peb;k 2') + out.Check(r'Ldr\.InMemoryOrderModuleList:.*\d+ \. \d+', + 'PEB_LDR_DATA saved') + out.Check(r'ntdll\.dll', 'ntdll present', re.IGNORECASE) + + # Check that there is no stack trace in the self-destroyed process. Confirm + # that the top is where we expect it (that's based only on IP), but + # subsequent stack entries will not be available. This confirms that we have + # a mostly valid dump, but that the stack was omitted. + out.Check( + r'self_destroying_program!crashpad::`anonymous namespace\'::' + r'FreeOwnStackAndBreak.*\nquit:', + 'at correct location, no additional stack entries') + + # Dump memory pointed to be EDI on the background suspended thread. We don't + # know the index of the thread because the system may have started other + # threads, so first do a run to extract the thread index that's suspended, + # and then another run to dump the data pointed to by EDI for that thread. + out = CdbRun(cdb_path, dump_path, '.ecxr;~') + match_obj = out.Find(r'(\d+)\s+Id: [0-9a-f.]+ Suspend: 1 Teb:') if match_obj: - if match_obj.group(1) != '0': - out.Check(r'FAILED', 'all suspend counts should be 0') - else: - count += 1 - else: - break - assert count > 2 + thread = match_obj.group(1) + out = CdbRun(cdb_path, dump_path, '.ecxr;~' + thread + 's;db /c14 edi') + out.Check(r'63 62 61 60 5f 5e 5d 5c-5b 5a 59 58 57 56 55 54 53 52 51 50', + 'data pointed to by registers captured') - out = CdbRun(cdb_path, other_program_no_exception_path, '.ecxr;k') - out.Check('Unknown exception - code 0cca11ed', - 'other program with no exception given') - out.Check('!RaiseException', 'other program in RaiseException()') + # Move up one stack frame after jumping to the exception, and examine + # memory. + out = CdbRun(cdb_path, dump_path, + '.ecxr; .f+; dd /c100 poi(offset_pointer)-20') + out.Check( + r'80000078 00000079 8000007a 0000007b 8000007c 0000007d 8000007e ' + r'0000007f 80000080 00000081 80000082 00000083 80000084 00000085 ' + r'80000086 00000087 80000088 00000089 8000008a 0000008b 8000008c ' + r'0000008d 8000008e 0000008f 80000090 00000091 80000092 00000093 ' + r'80000094 00000095 80000096 00000097', + 'data pointed to by stack captured') - out = CdbRun(cdb_path, sigabrt_main_path, '.ecxr') - out.Check('code 40000015', 'got sigabrt signal') - out.Check('::HandleAbortSignal', ' stack in expected location') + # Attempt to retrieve the value of g_extra_memory_pointer (by name), and + # then examine the memory at which it points. Both should have been saved. + out = CdbRun( + cdb_path, dump_path, + 'dd poi(crashy_program!crashpad::g_extra_memory_pointer)+0x1f30 ' + 'L8') + out.Check(r'0000655e 0000656b 00006578 00006585', + 'extra memory range captured') - out = CdbRun(cdb_path, sigabrt_background_path, '.ecxr') - out.Check('code 40000015', 'got sigabrt signal from background thread') + out = CdbRun(cdb_path, dump_path, '.dumpdebug') + 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') + + out = CdbRun(cdb_path, other_program_path, '.ecxr;k;~') + out.Check('Unknown exception - code deadbea7', + 'other program dump exception code') + out.Check('!Sleep', 'other program reasonable location') + out.Check("hanging_program!`anonymous namespace'::Thread1", + 'other program dump right thread') + count = 0 + while True: + match_obj = out.Find(r'Id.*Suspend: (\d+) ') + if match_obj: + if match_obj.group(1) != '0': + out.Check(r'FAILED', 'all suspend counts should be 0') + else: + count += 1 + else: + break + assert count > 2 + + out = CdbRun(cdb_path, other_program_no_exception_path, '.ecxr;k') + out.Check('Unknown exception - code 0cca11ed', + 'other program with no exception given') + out.Check('!RaiseException', 'other program in RaiseException()') + + out = CdbRun(cdb_path, sigabrt_main_path, '.ecxr') + out.Check('code 40000015', 'got sigabrt signal') + out.Check('::HandleAbortSignal', ' stack in expected location') + + out = CdbRun(cdb_path, sigabrt_background_path, '.ecxr') + out.Check('code 40000015', 'got sigabrt signal from background thread') def main(args): - try: - if len(args) != 1: - print('must supply binary dir', file=sys.stderr) - return 1 + try: + if len(args) != 1: + print('must supply binary dir', file=sys.stderr) + return 1 - cdb_path = GetCdbPath() - if not cdb_path: - print('could not find cdb', file=sys.stderr) - return 1 + cdb_path = GetCdbPath() + if not cdb_path: + print('could not find cdb', file=sys.stderr) + return 1 - # Make sure we can download Windows symbols. - if not os.environ.get('_NT_SYMBOL_PATH'): - symbol_dir = MakeTempDir() - protocol = 'https' if platform.win32_ver()[0] != 'XP' else 'http' - os.environ['_NT_SYMBOL_PATH'] = ( - 'SRV*' + symbol_dir + '*' + - protocol + '://msdl.microsoft.com/download/symbols') + # Make sure we can download Windows symbols. + if not os.environ.get('_NT_SYMBOL_PATH'): + symbol_dir = MakeTempDir() + protocol = 'https' if platform.win32_ver()[0] != 'XP' else 'http' + os.environ['_NT_SYMBOL_PATH'] = ( + 'SRV*' + symbol_dir + '*' + protocol + + '://msdl.microsoft.com/download/symbols') - pipe_name = r'\\.\pipe\end-to-end_%s_%s' % ( - os.getpid(), str(random.getrandbits(64))) + pipe_name = r'\\.\pipe\end-to-end_%s_%s' % (os.getpid(), + str(random.getrandbits(64))) - crashy_dump_path = GetDumpFromCrashyProgram(args[0], pipe_name) - if not crashy_dump_path: - return 1 + crashy_dump_path = GetDumpFromCrashyProgram(args[0], pipe_name) + if not crashy_dump_path: + return 1 - start_handler_dump_path = GetDumpFromCrashyProgram(args[0], None) - if not start_handler_dump_path: - return 1 + start_handler_dump_path = GetDumpFromCrashyProgram(args[0], None) + if not start_handler_dump_path: + return 1 - destroyed_dump_path = GetDumpFromSelfDestroyingProgram(args[0], pipe_name) - if not destroyed_dump_path: - return 1 + destroyed_dump_path = GetDumpFromSelfDestroyingProgram( + args[0], pipe_name) + 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 + 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 - other_program_path = GetDumpFromOtherProgram(args[0], pipe_name) - if not other_program_path: - return 1 + other_program_path = GetDumpFromOtherProgram(args[0], pipe_name) + if not other_program_path: + return 1 - other_program_no_exception_path = GetDumpFromOtherProgram( - args[0], pipe_name, 'noexception') - if not other_program_no_exception_path: - return 1 + other_program_no_exception_path = GetDumpFromOtherProgram( + args[0], pipe_name, 'noexception') + if not other_program_no_exception_path: + return 1 - sigabrt_main_path = GetDumpFromSignal(args[0], pipe_name, 'main') - if not sigabrt_main_path: - return 1 + sigabrt_main_path = GetDumpFromSignal(args[0], pipe_name, 'main') + if not sigabrt_main_path: + return 1 - sigabrt_background_path = GetDumpFromSignal( - args[0], pipe_name, 'background') - if not sigabrt_background_path: - return 1 + sigabrt_background_path = GetDumpFromSignal(args[0], pipe_name, + 'background') + 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) + 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) - return 1 if g_had_failures else 0 - finally: - CleanUpTempDirs() + return 1 if g_had_failures else 0 + finally: + CleanUpTempDirs() if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + sys.exit(main(sys.argv[1:])) diff --git a/third_party/fuchsia/runner.py b/third_party/fuchsia/runner.py old mode 100644 new mode 100755 index da4ec99a..229d8a42 --- a/third_party/fuchsia/runner.py +++ b/third_party/fuchsia/runner.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + # Copyright 2018 The Crashpad Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,4 +16,5 @@ import os import sys + os.execv(sys.argv[1], sys.argv[1:]) diff --git a/util/mach/mig.py b/util/mach/mig.py index dc9b7c64..fa35e006 100755 --- a/util/mach/mig.py +++ b/util/mach/mig.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# coding: utf-8 # Copyright 2019 The Crashpad Authors. All rights reserved. # @@ -20,6 +19,7 @@ import sys import mig_fix import mig_gen + def main(args): parsed = mig_gen.parse_args(args) @@ -30,5 +30,6 @@ def main(args): parsed.migcom_path, parsed.arch) mig_fix.fix_interface(interface) + if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/util/mach/mig_fix.py b/util/mach/mig_fix.py index 8cd5e4f6..037746fa 100755 --- a/util/mach/mig_fix.py +++ b/util/mach/mig_fix.py @@ -22,18 +22,18 @@ import sys from mig_gen import MigInterface + def _fix_user_implementation(implementation, fixed_implementation, header, fixed_header): """Rewrites a MIG-generated user implementation (.c) file. - Rewrites the file at |implementation| by adding - “__attribute__((unused))” to the definition of any structure typedefed - as “__Reply” by searching for the pattern unique to those structure - definitions. These structures are in fact 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. + Rewrites the file at |implementation| by adding “__attribute__((unused))” to + the definition of any structure typedefed as “__Reply” by searching for the + pattern unique to those structure definitions. These structures are in fact + 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. If |fixed_implementation| is None, overwrites the original; otherwise, puts the result in the file at |fixed_implementation|. @@ -59,6 +59,7 @@ def _fix_user_implementation(implementation, fixed_implementation, header, file.write(contents) file.close() + def _fix_server_implementation(implementation, fixed_implementation, header, fixed_header): """Rewrites a MIG-generated server implementation (.c) file. @@ -79,24 +80,25 @@ def _fix_server_implementation(implementation, fixed_implementation, header, contents = file.read() # Find interesting declarations. - declaration_pattern = \ - re.compile('^mig_internal (kern_return_t __MIG_check__.*)$', - re.MULTILINE) + declaration_pattern = re.compile( + '^mig_internal (kern_return_t __MIG_check__.*)$', re.MULTILINE) declarations = declaration_pattern.findall(contents) # Remove “__attribute__((__unused__))” from the declarations, and call them # “mig_external” or “extern” depending on whether “mig_external” is defined. attribute_pattern = re.compile(r'__attribute__\(\(__unused__\)\) ') - declarations = ['''\ + declarations = [ + '''\ #ifdef mig_external mig_external #else extern #endif -''' + attribute_pattern.sub('', x) + ';\n' for x in declarations] +''' + attribute_pattern.sub('', x) + ';\n' for x in declarations + ] # Rewrite the declarations in this file as “mig_external”. - contents = declaration_pattern.sub(r'mig_external \1', contents); + contents = declaration_pattern.sub(r'mig_external \1', contents) # Crashpad never implements the mach_msg_server() MIG callouts. To avoid # needing to provide stub implementations, set KERN_FAILURE as the RetCode @@ -125,6 +127,7 @@ extern file.close() return declarations + def _fix_header(header, fixed_header, declarations=[]): """Rewrites a MIG-generated header (.h) file. @@ -161,6 +164,7 @@ extern "C" { file.write(contents) file.close() + def fix_interface(interface, fixed_interface=None): if fixed_interface is None: fixed_interface = MigInterface(None, None, None, None) @@ -175,6 +179,7 @@ def fix_interface(interface, fixed_interface=None): _fix_header(interface.server_h, fixed_interface.server_h, server_declarations) + def main(args): parser = argparse.ArgumentParser() parser.add_argument('user_c') @@ -187,11 +192,12 @@ def main(args): parser.add_argument('--fixed_server_h', default=None) parsed = parser.parse_args(args) - interface = MigInterface(parsed.user_c, parsed.server_c, - parsed.user_h, parsed.server_h) + interface = MigInterface(parsed.user_c, parsed.server_c, parsed.user_h, + parsed.server_h) fixed_interface = MigInterface(parsed.fixed_user_c, parsed.fixed_server_c, parsed.fixed_user_h, parsed.fixed_server_h) fix_interface(interface, fixed_interface) + if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/util/mach/mig_gen.py b/util/mach/mig_gen.py index b3e9a5b4..dcbf8296 100755 --- a/util/mach/mig_gen.py +++ b/util/mach/mig_gen.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# coding: utf-8 # Copyright 2019 The Crashpad Authors. All rights reserved. # @@ -21,19 +20,30 @@ import os import subprocess import sys -MigInterface = collections.namedtuple('MigInterface', ['user_c', 'server_c', - 'user_h', 'server_h']) +MigInterface = collections.namedtuple( + 'MigInterface', ['user_c', 'server_c', 'user_h', 'server_h']) -def generate_interface(defs, interface, includes=[], sdk=None, clang_path=None, - mig_path=None, migcom_path=None, arch=None): + +def generate_interface(defs, + interface, + includes=[], + sdk=None, + clang_path=None, + mig_path=None, + migcom_path=None, + arch=None): if mig_path is None: - mig_path = 'mig' - command = [mig_path, - '-user', interface.user_c, - '-server', interface.server_c, - '-header', interface.user_h, - '-sheader', interface.server_h, - ] + mig_path = 'mig' + + # yapf: disable + command = [ + mig_path, + '-user', interface.user_c, + '-server', interface.server_c, + '-header', interface.user_h, + '-sheader', interface.server_h, + ] + # yapf: enable if clang_path is not None: os.environ['MIGCC'] = clang_path @@ -48,6 +58,7 @@ def generate_interface(defs, interface, includes=[], sdk=None, clang_path=None, command.append(defs) subprocess.check_call(command) + def parse_args(args): parser = argparse.ArgumentParser() parser.add_argument('--clang-path', help='Path to Clang') @@ -66,13 +77,15 @@ def parse_args(args): parser.add_argument('server_h') return parser.parse_args(args) + def main(args): parsed = parse_args(args) - interface = MigInterface(parsed.user_c, parsed.server_c, - parsed.user_h, parsed.server_h) - generate_interface(parsed.defs, interface, parsed.include, - parsed.sdk, parsed.clang_path, parsed.mig_path, - parsed.migcom_path, parsed.arch) + interface = MigInterface(parsed.user_c, parsed.server_c, parsed.user_h, + parsed.server_h) + generate_interface(parsed.defs, interface, parsed.include, parsed.sdk, + parsed.clang_path, parsed.mig_path, parsed.migcom_path, + parsed.arch) + if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/util/net/generate_test_server_key.py b/util/net/generate_test_server_key.py index 31d73c9a..3db08ade 100755 --- a/util/net/generate_test_server_key.py +++ b/util/net/generate_test_server_key.py @@ -23,25 +23,28 @@ key = os.path.join(testdata, 'crashpad_util_test_key.pem') cert = os.path.join(testdata, 'crashpad_util_test_cert.pem') with open(cert, 'w') as cert_file, open(key, 'w') as key_file: - MESSAGE = 'DO NOT EDIT: This file was auto-generated by ' + __file__ + '\n\n' - cert_file.write(MESSAGE) - key_file.write(MESSAGE) + MESSAGE = ('DO NOT EDIT: This file was auto-generated by ' + __file__ + + '\n\n') + cert_file.write(MESSAGE) + key_file.write(MESSAGE) - proc = subprocess.Popen( - ['openssl', 'req', '-x509', '-nodes', '-subj', '/CN=localhost', - '-days', '3650', '-newkey', 'rsa:2048', '-keyout', '-'], - stderr=open(os.devnull, 'w'), stdout=subprocess.PIPE) + proc = subprocess.Popen([ + 'openssl', 'req', '-x509', '-nodes', '-subj', '/CN=localhost', '-days', + '3650', '-newkey', 'rsa:2048', '-keyout', '-' + ], + stderr=open(os.devnull, 'w'), + stdout=subprocess.PIPE) - contents = proc.communicate()[0] - dest = sys.stderr - for line in contents.splitlines(True): - if line.startswith("-----BEGIN PRIVATE KEY-----"): - dest = key_file - elif line.startswith("-----BEGIN CERTIFICATE-----"): - dest = cert_file - elif line.startswith("-----END"): - dest.write(line) - dest = sys.stderr - continue + contents = proc.communicate()[0] + dest = sys.stderr + for line in contents.splitlines(True): + if line.startswith("-----BEGIN PRIVATE KEY-----"): + dest = key_file + elif line.startswith("-----BEGIN CERTIFICATE-----"): + dest = cert_file + elif line.startswith("-----END"): + dest.write(line) + dest = sys.stderr + continue - dest.write(line) + dest.write(line) From ecc41d022953306c4ef0251dad4d5433daacd4be Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 27 Apr 2020 10:54:20 -0400 Subject: [PATCH 400/401] doc: Update Doxygen to 1.8.18 and fix Doxygen warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % doxygen -u doc/support/crashpad.doxy […warnings about removing obsolete TCL_SUBST, PERL_PATH, MSCGEN_PATH…] Configuration file 'doc/support/crashpad.doxy' updated. % doxygen -v 1.8.18 Change-Id: I771f654713042b0040873355051b9efaf46bffd1 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2165817 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- client/crashpad_info.h | 38 ++-- doc/support/crashpad.doxy | 202 ++++++++++++------ .../sanitized/process_snapshot_sanitized.h | 2 + util/linux/proc_task_reader.h | 3 +- 4 files changed, 158 insertions(+), 87 deletions(-) diff --git a/client/crashpad_info.h b/client/crashpad_info.h index 4c1633f0..ed7b9c14 100644 --- a/client/crashpad_info.h +++ b/client/crashpad_info.h @@ -141,15 +141,15 @@ struct CrashpadInfo { //! //! When handling an exception, the Crashpad handler will scan all modules in //! a process. The first one that has a CrashpadInfo structure populated with - //! a value other than #kUnset for this field will dictate whether the handler - //! is functional or not. If all modules with a CrashpadInfo structure specify - //! #kUnset, the handler will be enabled. If disabled, the Crashpad handler - //! will still run and receive exceptions, but will not take any action on an - //! exception on its own behalf, except for the action necessary to determine - //! that it has been disabled. + //! a value other than TriState::kUnset for this field will dictate whether + //! the handler is functional or not. If all modules with a CrashpadInfo + //! structure specify TriState::kUnset, the handler will be enabled. If + //! disabled, the Crashpad handler will still run and receive exceptions, but + //! will not take any action on an exception on its own behalf, except for the + //! action necessary to determine that it has been disabled. //! - //! The Crashpad handler should not normally be disabled. More commonly, it - //! is appropriate to disable crash report upload by calling + //! The Crashpad handler should not normally be disabled. More commonly, it is + //! appropriate to disable crash report upload by calling //! Settings::SetUploadsEnabled(). void set_crashpad_handler_behavior(TriState crashpad_handler_behavior) { crashpad_handler_behavior_ = crashpad_handler_behavior; @@ -160,15 +160,15 @@ struct CrashpadInfo { //! //! When handling an exception, the Crashpad handler will scan all modules in //! a process. The first one that has a CrashpadInfo structure populated with - //! a value other than #kUnset for this field will dictate whether the - //! exception is forwarded to the system’s crash reporter. If all modules with - //! a CrashpadInfo structure specify #kUnset, forwarding will be enabled. - //! Unless disabled, forwarding may still occur if the Crashpad handler is - //! disabled by SetCrashpadHandlerState(). Even when forwarding is enabled, - //! the Crashpad handler may choose not to forward all exceptions to the - //! system’s crash reporter in cases where it has reason to believe that the - //! system’s crash reporter would not normally have handled the exception in - //! Crashpad’s absence. + //! a value other than TriState::kUnset for this field will dictate whether + //! the exception is forwarded to the system’s crash reporter. If all modules + //! with a CrashpadInfo structure specify TriState::kUnset, forwarding will be + //! enabled. Unless disabled, forwarding may still occur if the Crashpad + //! handler is disabled by SetCrashpadHandlerState(). Even when forwarding is + //! enabled, the Crashpad handler may choose not to forward all exceptions to + //! the system’s crash reporter in cases where it has reason to believe that + //! the system’s crash reporter would not normally have handled the exception + //! in Crashpad’s absence. void set_system_crash_reporter_forwarding( TriState system_crash_reporter_forwarding) { system_crash_reporter_forwarding_ = system_crash_reporter_forwarding; @@ -179,8 +179,8 @@ struct CrashpadInfo { //! //! When handling an exception, the Crashpad handler will scan all modules in //! a process. The first one that has a CrashpadInfo structure populated with - //! a value other than #kUnset for this field will dictate whether the extra - //! memory is captured. + //! a value other than TriState::kUnset for this field will dictate whether + //! the extra memory is captured. //! //! This causes Crashpad to include pages of data referenced by locals or //! other stack memory. Turning this on can increase the size of the minidump diff --git a/doc/support/crashpad.doxy b/doc/support/crashpad.doxy index 2f3e2bb2..ca1ea251 100644 --- a/doc/support/crashpad.doxy +++ b/doc/support/crashpad.doxy @@ -1,4 +1,4 @@ -# Doxyfile 1.8.14 +# Doxyfile 1.8.18 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -17,10 +17,10 @@ # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See # https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. @@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -181,6 +189,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -230,15 +248,13 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines (in the resulting output). You can put ^^ in the value part of an # alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -267,17 +283,26 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # @@ -288,7 +313,7 @@ EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -300,7 +325,7 @@ MARKDOWN_SUPPORT = YES # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 0. +# Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 0 @@ -436,6 +461,12 @@ EXTRACT_ALL = NO EXTRACT_PRIVATE = NO +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. @@ -490,8 +521,8 @@ HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO, these declarations will be -# included in the documentation. +# declarations. If set to NO, these declarations will be included in the +# documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO @@ -514,7 +545,7 @@ INTERNAL_DOCS = NO # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# (including Cygwin) ands Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES @@ -746,7 +777,8 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. # The default value is: NO. WARN_NO_PARAMDOC = NO @@ -805,8 +837,10 @@ INPUT_ENCODING = UTF-8 # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, -# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. +# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), +# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen +# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.c \ *.cc \ @@ -968,7 +1002,7 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO @@ -1005,7 +1039,7 @@ SOURCE_TOOLTIPS = YES # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -1183,9 +1217,9 @@ HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that -# are dynamically created via Javascript. If disabled, the navigation index will +# are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML -# page. Disable this option to support browsers that do not have Javascript, +# page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1215,13 +1249,13 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: https://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1260,7 +1294,7 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output @@ -1336,7 +1370,7 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace). +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1344,7 +1378,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders). +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- +# folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1352,21 +1387,23 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- +# filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = @@ -1450,6 +1487,17 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png The default and svg Looks nicer but requires the +# pdf2svg tool. +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1470,8 +1518,14 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# https://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1499,7 +1553,7 @@ MATHJAX_FORMAT = HTML-CSS # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/. +# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest @@ -1541,7 +1595,7 @@ MATHJAX_CODEFILE = SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a web server instead of a web client using Javascript. There +# implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing @@ -1625,21 +1679,35 @@ LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. @@ -1774,6 +1842,14 @@ LATEX_BIB_STYLE = plain LATEX_TIMESTAMP = NO +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -1813,9 +1889,9 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. @@ -1824,8 +1900,8 @@ RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = @@ -1911,6 +1987,13 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- @@ -2116,12 +2199,6 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2135,15 +2212,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. diff --git a/snapshot/sanitized/process_snapshot_sanitized.h b/snapshot/sanitized/process_snapshot_sanitized.h index 4e7e6d6a..2d387981 100644 --- a/snapshot/sanitized/process_snapshot_sanitized.h +++ b/snapshot/sanitized/process_snapshot_sanitized.h @@ -50,6 +50,8 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot { //! \param[in] annotations_whitelist A list of annotations names to allow to //! be returned by AnnotationsSimpleMap() or from this object's module //! snapshots. If `nullptr`, all annotations will be returned. + //! \param[in] memory_range_whitelist A list of memory ranges to allow to be + //! accessible via Memory(), or `nullptr` to allow all ranges. //! \param[in] target_module_address An address in the target process' //! address space within the bounds of a module to target. If the //! crashing thread's context and stack do not contain any pointers into diff --git a/util/linux/proc_task_reader.h b/util/linux/proc_task_reader.h index 71287d92..9b95f127 100644 --- a/util/linux/proc_task_reader.h +++ b/util/linux/proc_task_reader.h @@ -21,7 +21,8 @@ namespace crashpad { -//! \brief Enumerates the thread IDs of a process by reading /proc/<pid>/task. +//! \brief Enumerates the thread IDs of a process by reading +//! <code>/proc/<i>pid</i>/task</code>. //! //! \param[in] pid The process ID for which to read thread IDs. //! \param[out] tids The read thread IDs. From bac601e785fc85bd83dd98239514ea3bfc645635 Mon Sep 17 00:00:00 2001 From: Mark Mentovai <mark@chromium.org> Date: Mon, 27 Apr 2020 10:35:35 -0400 Subject: [PATCH 401/401] Use underscores instead of hyphens in filenames Change-Id: I886a5cfc8092eb680163586b5855a86d407a34a8 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2165816 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org> --- DEPS | 2 +- build/ios/{setup-ios-gn.config => setup_ios_gn.config} | 0 build/ios/{setup-ios-gn.py => setup_ios_gn.py} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename build/ios/{setup-ios-gn.config => setup_ios_gn.config} (100%) rename build/ios/{setup-ios-gn.py => setup_ios_gn.py} (100%) diff --git a/DEPS b/DEPS index 0065e3c5..81b9583b 100644 --- a/DEPS +++ b/DEPS @@ -193,7 +193,7 @@ hooks = [ 'condition': 'run_setup_ios_gn and checkout_ios', 'action': [ 'python', - 'crashpad/build/ios/setup-ios-gn.py' + 'crashpad/build/ios/setup_ios_gn.py' ], }, ] diff --git a/build/ios/setup-ios-gn.config b/build/ios/setup_ios_gn.config similarity index 100% rename from build/ios/setup-ios-gn.config rename to build/ios/setup_ios_gn.config diff --git a/build/ios/setup-ios-gn.py b/build/ios/setup_ios_gn.py similarity index 100% rename from build/ios/setup-ios-gn.py rename to build/ios/setup_ios_gn.py