| // 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 <mach-o/loader.h> |
| #include <mach/mach.h> |
| |
| #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<uint8_t>& 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<uint16_t>(&type)) { |
| const std::vector<uint8_t>& 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<uint8_t> ModuleSnapshotIOSIntermediateDump::BuildID() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return std::vector<uint8_t>(); |
| } |
| |
| std::vector<std::string> ModuleSnapshotIOSIntermediateDump::AnnotationsVector() |
| const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return annotations_vector_; |
| } |
| |
| std::map<std::string, std::string> |
| ModuleSnapshotIOSIntermediateDump::AnnotationsSimpleMap() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return annotations_simple_map_; |
| } |
| |
| std::vector<AnnotationSnapshot> |
| ModuleSnapshotIOSIntermediateDump::AnnotationObjects() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return annotation_objects_; |
| } |
| |
| std::set<CheckedRange<uint64_t>> |
| ModuleSnapshotIOSIntermediateDump::ExtraMemoryRanges() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return std::set<CheckedRange<uint64_t>>(); |
| } |
| |
| std::vector<const UserMinidumpStream*> |
| ModuleSnapshotIOSIntermediateDump::CustomMinidumpStreams() const { |
| return std::vector<const UserMinidumpStream*>(); |
| } |
| |
| } // namespace internal |
| } // namespace crashpad |