From b109e4ce389775651eb2cdb3cc1ffb95ab808d3b Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Wed, 4 Mar 2020 15:19:46 -0500 Subject: [PATCH] [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 Commit-Queue: Justin Cohen --- 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 +#include + +#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(&dyld_info), + &count); + if (kr != KERN_SUCCESS) { + MACH_LOG(WARNING, kr) << "task_info"; + return 0; + } + + return reinterpret_cast(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(images->dyldImageLoadAddress); + return FinishInitialization(); +} + +bool ModuleSnapshotIOS::Initialize(const dyld_image_info* image) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + name_ = image->imageFilePath; + address_ = FromPointerCast(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(address_); + const load_command* command = + reinterpret_cast(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(&command); + if (strcmp(segment->segname, SEG_TEXT) == 0) { + size_ = segment->vmsize; + } + } else if (command->cmd == LC_ID_DYLIB) { + dylib_command* dylib = reinterpret_cast(&command); + dylib_version_ = dylib->dylib.current_version; + } else if (command->cmd == LC_SOURCE_VERSION) { + source_version_command* source_version = + reinterpret_cast(&command); + source_version_ = source_version->version; + } else if (command->cmd == LC_UUID) { + uuid_command* uuid = reinterpret_cast(&command); + uuid_.InitializeFromBytes(uuid->uuid); + } + + command = reinterpret_cast( + reinterpret_cast(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 ModuleSnapshotIOS::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + +std::vector ModuleSnapshotIOS::AnnotationsVector() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + +std::map ModuleSnapshotIOS::AnnotationsSimpleMap() + const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::map(); +} + +std::vector ModuleSnapshotIOS::AnnotationObjects() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + +std::set> ModuleSnapshotIOS::ExtraMemoryRanges() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::set>(); +} + +std::vector +ModuleSnapshotIOS::CustomMinidumpStreams() const { + return std::vector(); +} + +} // 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 +#include +#include + +#include +#include +#include + +#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 BuildID() const override; + std::vector AnnotationsVector() const override; + std::map AnnotationsSimpleMap() const override; + std::vector AnnotationObjects() const override; + std::set> ExtraMemoryRanges() const override; + std::vector 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 +#include + +#include + +#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& +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 ProcessSnapshotIOS::Threads() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + +std::vector ProcessSnapshotIOS::Modules() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + std::vector modules; + for (const auto& module : modules_) { + modules.push_back(module.get()); + } + return modules; +} + +std::vector ProcessSnapshotIOS::UnloadedModules() + const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + +const ExceptionSnapshot* ProcessSnapshotIOS::Exception() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return nullptr; +} + +std::vector ProcessSnapshotIOS::MemoryMap() + const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + +std::vector ProcessSnapshotIOS::Handles() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + +std::vector ProcessSnapshotIOS::ExtraMemory() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + +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(); + if (module->Initialize(image)) { + modules_.push_back(std::move(module)); + } + } + auto module = std::make_unique(); + 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 + +#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& AnnotationsSimpleMap() + const override; + const SystemSnapshot* System() const override; + std::vector Threads() const override; + std::vector Modules() const override; + std::vector UnloadedModules() const override; + const ExceptionSnapshot* Exception() const override; + std::vector MemoryMap() const override; + std::vector Handles() const override; + std::vector ExtraMemory() const override; + const ProcessMemory* Memory() const override; + + private: + // Initializes modules_ on behalf of Initialize(). + void InitializeModules(); + + std::vector> modules_; + UUID report_id_; + UUID client_id_; + std::map annotations_simple_map_; + timeval snapshot_time_; + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ProcessSnapshotIOS); +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_IOS_PROCESS_SNAPSHOT_IOS_H_