// 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) { const segment_command_64* segment = reinterpret_cast(command); if (strcmp(segment->segname, SEG_TEXT) == 0) { size_ = segment->vmsize; } } else if (command->cmd == LC_ID_DYLIB) { const dylib_command* dylib = reinterpret_cast(command); dylib_version_ = dylib->dylib.current_version; } else if (command->cmd == LC_SOURCE_VERSION) { const source_version_command* source_version = reinterpret_cast(command); source_version_ = source_version->version; } else if (command->cmd == LC_UUID) { const 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