| // Copyright 2015 The Crashpad Authors |
| // |
| // 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/module_snapshot_minidump.h" |
| |
| #include <stddef.h> |
| #include <string.h> |
| |
| #include "base/check_op.h" |
| #include "base/logging.h" |
| #include "base/notreached.h" |
| #include "minidump/minidump_extensions.h" |
| #include "snapshot/minidump/minidump_annotation_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 { |
| namespace internal { |
| |
| ModuleSnapshotMinidump::ModuleSnapshotMinidump() |
| : ModuleSnapshot(), |
| minidump_module_(), |
| annotations_vector_(), |
| annotations_simple_map_(), |
| annotation_objects_(), |
| uuid_(), |
| build_id_(), |
| name_(), |
| debug_file_name_(), |
| age_(0), |
| initialized_() {} |
| |
| ModuleSnapshotMinidump::~ModuleSnapshotMinidump() {} |
| |
| bool ModuleSnapshotMinidump::Initialize( |
| FileReaderInterface* file_reader, |
| RVA minidump_module_rva, |
| const MINIDUMP_LOCATION_DESCRIPTOR* |
| minidump_module_crashpad_info_location) { |
| INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| |
| if (!file_reader->SeekSet(minidump_module_rva)) { |
| return false; |
| } |
| |
| if (!file_reader->ReadExactly(&minidump_module_, sizeof(minidump_module_))) { |
| return false; |
| } |
| |
| if (!InitializeModuleCrashpadInfo(file_reader, |
| minidump_module_crashpad_info_location)) { |
| return false; |
| } |
| |
| ReadMinidumpUTF16String(file_reader, minidump_module_.ModuleNameRva, &name_); |
| |
| 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) + 1) { |
| 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; |
| |
| if (cv_record.back() != '\0') { |
| LOG(ERROR) << "CodeView record marked as PDB70 missing NUL-terminator in " |
| "pdb_name"; |
| return false; |
| } |
| |
| std::copy(cv_record.begin() + offsetof(CodeViewRecordPDB70, pdb_name), |
| cv_record.end() - 1, |
| 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_; |
| } |
| |
| uint64_t ModuleSnapshotMinidump::Address() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return minidump_module_.BaseOfImage; |
| } |
| |
| uint64_t ModuleSnapshotMinidump::Size() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return minidump_module_.SizeOfImage; |
| } |
| |
| time_t ModuleSnapshotMinidump::Timestamp() const { |
| return minidump_module_.TimeDateStamp; |
| } |
| |
| void ModuleSnapshotMinidump::FileVersion(uint16_t* version_0, |
| uint16_t* version_1, |
| uint16_t* version_2, |
| uint16_t* version_3) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 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, |
| uint16_t* version_1, |
| uint16_t* version_2, |
| uint16_t* version_3) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 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_); |
| 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_); |
| *uuid = uuid_; |
| *age = age_; |
| } |
| |
| std::string ModuleSnapshotMinidump::DebugFileName() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 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 { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return annotations_vector_; |
| } |
| |
| std::map<std::string, std::string> |
| ModuleSnapshotMinidump::AnnotationsSimpleMap() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return annotations_simple_map_; |
| } |
| |
| std::vector<AnnotationSnapshot> ModuleSnapshotMinidump::AnnotationObjects() |
| const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return annotation_objects_; |
| } |
| |
| std::set<CheckedRange<uint64_t>> ModuleSnapshotMinidump::ExtraMemoryRanges() |
| const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| NOTREACHED_IN_MIGRATION(); // https://crashpad.chromium.org/bug/10 |
| return std::set<CheckedRange<uint64_t>>(); |
| } |
| |
| std::vector<const UserMinidumpStream*> |
| ModuleSnapshotMinidump::CustomMinidumpStreams() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| NOTREACHED_IN_MIGRATION(); // https://crashpad.chromium.org/bug/10 |
| return std::vector<const UserMinidumpStream*>(); |
| } |
| |
| bool ModuleSnapshotMinidump::InitializeModuleCrashpadInfo( |
| FileReaderInterface* file_reader, |
| const MINIDUMP_LOCATION_DESCRIPTOR* |
| minidump_module_crashpad_info_location) { |
| if (!minidump_module_crashpad_info_location || |
| minidump_module_crashpad_info_location->Rva == 0) { |
| return true; |
| } |
| |
| MinidumpModuleCrashpadInfo minidump_module_crashpad_info; |
| if (minidump_module_crashpad_info_location->DataSize < |
| sizeof(minidump_module_crashpad_info)) { |
| LOG(ERROR) << "minidump_module_crashpad_info size mismatch"; |
| return false; |
| } |
| |
| if (!file_reader->SeekSet(minidump_module_crashpad_info_location->Rva)) { |
| return false; |
| } |
| |
| if (!file_reader->ReadExactly(&minidump_module_crashpad_info, |
| sizeof(minidump_module_crashpad_info))) { |
| return false; |
| } |
| |
| if (minidump_module_crashpad_info.version != |
| MinidumpModuleCrashpadInfo::kVersion) { |
| LOG(ERROR) << "minidump_module_crashpad_info version mismatch"; |
| return false; |
| } |
| |
| if (!ReadMinidumpStringList(file_reader, |
| minidump_module_crashpad_info.list_annotations, |
| &annotations_vector_)) { |
| return false; |
| } |
| |
| if (!ReadMinidumpSimpleStringDictionary( |
| file_reader, |
| minidump_module_crashpad_info.simple_annotations, |
| &annotations_simple_map_)) { |
| return false; |
| } |
| |
| if (!ReadMinidumpAnnotationList( |
| file_reader, |
| minidump_module_crashpad_info.annotation_objects, |
| &annotation_objects_)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| } // namespace internal |
| } // namespace crashpad |