// 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_intermediate_dump.h" #include #include #include "base/files/file_path.h" #include "base/mac/mach_logging.h" #include "snapshot/ios/intermediate_dump_reader_util.h" #include "util/ios/ios_intermediate_dump_data.h" #include "util/ios/ios_intermediate_dump_list.h" #include "util/misc/from_pointer_cast.h" #include "util/misc/uuid.h" namespace crashpad { namespace internal { using Key = IntermediateDumpKey; ModuleSnapshotIOSIntermediateDump::ModuleSnapshotIOSIntermediateDump() : ModuleSnapshot(), name_(), address_(0), size_(0), timestamp_(0), dylib_version_(0), source_version_(0), filetype_(0), initialized_() {} ModuleSnapshotIOSIntermediateDump::~ModuleSnapshotIOSIntermediateDump() {} bool ModuleSnapshotIOSIntermediateDump::Initialize( const IOSIntermediateDumpMap* image_data) { INITIALIZATION_STATE_SET_INITIALIZING(initialized_); GetDataStringFromMap(image_data, Key::kName, &name_); GetDataValueFromMap(image_data, Key::kAddress, &address_); GetDataValueFromMap(image_data, Key::kSize, &size_); GetDataValueFromMap(image_data, Key::kSourceVersion, &source_version_); GetDataValueFromMap(image_data, Key::kFileType, &filetype_); // These keys are often missing. GetDataValueFromMap(image_data, Key::kTimestamp, ×tamp_, LogMissingDataValueFromMap::kDontLogIfMissing); GetDataValueFromMap(image_data, Key::kDylibCurrentVersion, &dylib_version_, LogMissingDataValueFromMap::kDontLogIfMissing); const IOSIntermediateDumpData* uuid_dump = GetDataFromMap(image_data, IntermediateDumpKey::kUUID); if (uuid_dump) { const std::vector& bytes = uuid_dump->bytes(); if (!bytes.data() || bytes.size() != 16) { LOG(ERROR) << "Invalid module uuid."; } else { uuid_.InitializeFromBytes(bytes.data()); } } const IOSIntermediateDumpList* annotation_list = image_data->GetAsList(IntermediateDumpKey::kAnnotationObjects); if (annotation_list) { for (auto& annotation : *annotation_list) { std::string name; if (!GetDataStringFromMap( annotation.get(), Key::kAnnotationName, &name) || name.empty() || name.length() > 64) { // Annotation::kNameMaxLength LOG(ERROR) << "Invalid annotation name length."; continue; } uint16_t type; const IOSIntermediateDumpData* type_dump = annotation->GetAsData(IntermediateDumpKey::kAnnotationType); const IOSIntermediateDumpData* value_dump = annotation->GetAsData(IntermediateDumpKey::kAnnotationValue); if (type_dump && value_dump && type_dump->GetValue(&type)) { const std::vector& bytes = value_dump->bytes(); uint64_t length = bytes.size(); if (!bytes.data() || length > 20480) { // Annotation::kValueMaxSize LOG(ERROR) << "Invalid annotation value length."; continue; } annotation_objects_.push_back(AnnotationSnapshot(name, type, bytes)); } } } const IOSIntermediateDumpList* simple_map_dump = image_data->GetAsList(IntermediateDumpKey::kAnnotationsSimpleMap); if (simple_map_dump) { for (auto& annotation : *simple_map_dump) { const IOSIntermediateDumpData* name_dump = annotation->GetAsData(IntermediateDumpKey::kAnnotationName); const IOSIntermediateDumpData* value_dump = annotation->GetAsData(IntermediateDumpKey::kAnnotationValue); if (name_dump && value_dump) { annotations_simple_map_.insert( make_pair(name_dump->GetString(), value_dump->GetString())); } } } const IOSIntermediateDumpMap* crash_info_dump = image_data->GetAsMap(IntermediateDumpKey::kAnnotationsCrashInfo); if (crash_info_dump) { const IOSIntermediateDumpData* message1_dump = crash_info_dump->GetAsData( IntermediateDumpKey::kAnnotationsCrashInfoMessage1); if (message1_dump) { std::string message1 = message1_dump->GetString(); if (!message1.empty()) annotations_vector_.push_back(message1); } const IOSIntermediateDumpData* message2_dump = crash_info_dump->GetAsData( IntermediateDumpKey::kAnnotationsCrashInfoMessage2); if (message2_dump) { std::string message2 = message2_dump->GetString(); if (!message2.empty()) annotations_vector_.push_back(message2); } } const IOSIntermediateDumpData* dyld_error_dump = image_data->GetAsData(IntermediateDumpKey::kAnnotationsDyldErrorString); if (dyld_error_dump) { std::string dyld_error_string = dyld_error_dump->GetString(); if (!dyld_error_string.empty()) annotations_vector_.push_back(dyld_error_string); } INITIALIZATION_STATE_SET_VALID(initialized_); return true; } std::string ModuleSnapshotIOSIntermediateDump::Name() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return name_; } uint64_t ModuleSnapshotIOSIntermediateDump::Address() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return address_; } uint64_t ModuleSnapshotIOSIntermediateDump::Size() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return size_; } time_t ModuleSnapshotIOSIntermediateDump::Timestamp() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return timestamp_; } void ModuleSnapshotIOSIntermediateDump::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 ModuleSnapshotIOSIntermediateDump::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 ModuleSnapshotIOSIntermediateDump::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 ModuleSnapshotIOSIntermediateDump::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); *uuid = uuid_; *age = 0; } std::string ModuleSnapshotIOSIntermediateDump::DebugFileName() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return base::FilePath(Name()).BaseName().value(); } std::vector ModuleSnapshotIOSIntermediateDump::BuildID() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return std::vector(); } std::vector ModuleSnapshotIOSIntermediateDump::AnnotationsVector() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return annotations_vector_; } std::map ModuleSnapshotIOSIntermediateDump::AnnotationsSimpleMap() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return annotations_simple_map_; } std::vector ModuleSnapshotIOSIntermediateDump::AnnotationObjects() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return annotation_objects_; } std::set> ModuleSnapshotIOSIntermediateDump::ExtraMemoryRanges() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return std::set>(); } std::vector ModuleSnapshotIOSIntermediateDump::CustomMinidumpStreams() const { return std::vector(); } } // namespace internal } // namespace crashpad