| // 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/process_snapshot_minidump.h" |
| |
| #include <utility> |
| |
| #include "base/logging.h" |
| #include "base/notreached.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "build/build_config.h" |
| #include "minidump/minidump_extensions.h" |
| #include "snapshot/memory_map_region_snapshot.h" |
| #include "snapshot/minidump/minidump_simple_string_dictionary_reader.h" |
| #include "snapshot/minidump/minidump_string_reader.h" |
| #include "util/file/file_io.h" |
| |
| namespace crashpad { |
| |
| namespace internal { |
| |
| class MemoryMapRegionSnapshotMinidump : public MemoryMapRegionSnapshot { |
| public: |
| MemoryMapRegionSnapshotMinidump(MINIDUMP_MEMORY_INFO info) : info_(info) {} |
| ~MemoryMapRegionSnapshotMinidump() override = default; |
| |
| const MINIDUMP_MEMORY_INFO& AsMinidumpMemoryInfo() const override { |
| return info_; |
| } |
| |
| private: |
| MINIDUMP_MEMORY_INFO info_; |
| }; |
| |
| } // namespace internal |
| |
| ProcessSnapshotMinidump::ProcessSnapshotMinidump() |
| : ProcessSnapshot(), |
| header_(), |
| stream_directory_(), |
| stream_map_(), |
| modules_(), |
| threads_(), |
| unloaded_modules_(), |
| mem_regions_(), |
| mem_regions_exposed_(), |
| custom_streams_(), |
| crashpad_info_(), |
| system_snapshot_(), |
| exception_snapshot_(), |
| arch_(CPUArchitecture::kCPUArchitectureUnknown), |
| annotations_simple_map_(), |
| file_reader_(nullptr), |
| process_id_(kInvalidProcessID), |
| create_time_(0), |
| user_time_(0), |
| kernel_time_(0), |
| initialized_() {} |
| |
| ProcessSnapshotMinidump::~ProcessSnapshotMinidump() {} |
| |
| bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { |
| INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| |
| file_reader_ = file_reader; |
| |
| if (!file_reader_->SeekSet(0)) { |
| return false; |
| } |
| |
| if (!file_reader_->ReadExactly(&header_, sizeof(header_))) { |
| return false; |
| } |
| |
| if (header_.Signature != MINIDUMP_SIGNATURE) { |
| LOG(ERROR) << "minidump signature mismatch"; |
| return false; |
| } |
| |
| if (header_.Version != MINIDUMP_VERSION) { |
| LOG(ERROR) << "minidump version mismatch"; |
| return false; |
| } |
| |
| if (!file_reader->SeekSet(header_.StreamDirectoryRva)) { |
| return false; |
| } |
| |
| stream_directory_.resize(header_.NumberOfStreams); |
| if (!stream_directory_.empty() && |
| !file_reader_->ReadExactly( |
| &stream_directory_[0], |
| header_.NumberOfStreams * sizeof(stream_directory_[0]))) { |
| return false; |
| } |
| |
| for (const MINIDUMP_DIRECTORY& directory : stream_directory_) { |
| const MinidumpStreamType stream_type = |
| static_cast<MinidumpStreamType>(directory.StreamType); |
| if (stream_map_.find(stream_type) != stream_map_.end()) { |
| LOG(ERROR) << "duplicate streams for type " << directory.StreamType; |
| return false; |
| } |
| |
| stream_map_[stream_type] = &directory.Location; |
| } |
| |
| if (!InitializeCrashpadInfo() || !InitializeMiscInfo() || |
| !InitializeModules() || !InitializeSystemSnapshot() || |
| !InitializeMemoryInfo() || !InitializeExtraMemory() || |
| !InitializeThreads() || !InitializeCustomMinidumpStreams() || |
| !InitializeExceptionSnapshot()) { |
| return false; |
| } |
| |
| INITIALIZATION_STATE_SET_VALID(initialized_); |
| return true; |
| } |
| |
| crashpad::ProcessID ProcessSnapshotMinidump::ProcessID() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return process_id_; |
| } |
| |
| crashpad::ProcessID ProcessSnapshotMinidump::ParentProcessID() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| NOTREACHED_IN_MIGRATION(); // https://crashpad.chromium.org/bug/10 |
| return 0; |
| } |
| |
| void ProcessSnapshotMinidump::SnapshotTime(timeval* snapshot_time) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| snapshot_time->tv_sec = header_.TimeDateStamp; |
| snapshot_time->tv_usec = 0; |
| } |
| |
| void ProcessSnapshotMinidump::ProcessStartTime(timeval* start_time) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| start_time->tv_sec = create_time_; |
| start_time->tv_usec = 0; |
| } |
| |
| void ProcessSnapshotMinidump::ProcessCPUTimes(timeval* user_time, |
| timeval* system_time) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| user_time->tv_sec = user_time_; |
| user_time->tv_usec = 0; |
| system_time->tv_sec = kernel_time_; |
| system_time->tv_usec = 0; |
| } |
| |
| void ProcessSnapshotMinidump::ReportID(UUID* report_id) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| *report_id = crashpad_info_.report_id; |
| } |
| |
| void ProcessSnapshotMinidump::ClientID(UUID* client_id) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| *client_id = crashpad_info_.client_id; |
| } |
| |
| const std::map<std::string, std::string>& |
| ProcessSnapshotMinidump::AnnotationsSimpleMap() const { |
| // TODO(mark): This method should not be const, although the interface |
| // currently imposes this requirement. Making it non-const would allow |
| // annotations_simple_map_ to be lazily constructed: InitializeCrashpadInfo() |
| // could be called here, and from other locations that require it, rather than |
| // calling it from Initialize(). |
| // https://crashpad.chromium.org/bug/9 |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return annotations_simple_map_; |
| } |
| |
| const SystemSnapshot* ProcessSnapshotMinidump::System() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return &system_snapshot_; |
| } |
| |
| std::vector<const ThreadSnapshot*> ProcessSnapshotMinidump::Threads() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| std::vector<const ThreadSnapshot*> threads; |
| for (const auto& thread : threads_) { |
| threads.push_back(thread.get()); |
| } |
| return threads; |
| } |
| |
| std::vector<const ModuleSnapshot*> ProcessSnapshotMinidump::Modules() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| std::vector<const ModuleSnapshot*> modules; |
| for (const auto& module : modules_) { |
| modules.push_back(module.get()); |
| } |
| return modules; |
| } |
| |
| std::vector<UnloadedModuleSnapshot> ProcessSnapshotMinidump::UnloadedModules() |
| const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| NOTREACHED_IN_MIGRATION(); // https://crashpad.chromium.org/bug/10 |
| return unloaded_modules_; |
| } |
| |
| const ExceptionSnapshot* ProcessSnapshotMinidump::Exception() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| if (exception_snapshot_.IsValid()) { |
| return &exception_snapshot_; |
| } |
| // Allow caller to know whether the minidump contained an exception stream. |
| return nullptr; |
| } |
| |
| std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotMinidump::MemoryMap() |
| const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return mem_regions_exposed_; |
| } |
| |
| std::vector<HandleSnapshot> ProcessSnapshotMinidump::Handles() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| NOTREACHED_IN_MIGRATION(); // https://crashpad.chromium.org/bug/10 |
| return std::vector<HandleSnapshot>(); |
| } |
| |
| std::vector<const MemorySnapshot*> ProcessSnapshotMinidump::ExtraMemory() |
| const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| std::vector<const MemorySnapshot*> chunks; |
| for (const auto& chunk : extra_memory_) { |
| chunks.push_back(chunk.get()); |
| } |
| return chunks; |
| } |
| |
| const ProcessMemory* ProcessSnapshotMinidump::Memory() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return nullptr; |
| } |
| |
| std::vector<const MinidumpStream*> |
| ProcessSnapshotMinidump::CustomMinidumpStreams() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| |
| std::vector<const MinidumpStream*> result; |
| result.reserve(custom_streams_.size()); |
| for (const auto& custom_stream : custom_streams_) { |
| result.push_back(custom_stream.get()); |
| } |
| return result; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeCrashpadInfo() { |
| const auto& stream_it = stream_map_.find(kMinidumpStreamTypeCrashpadInfo); |
| if (stream_it == stream_map_.end()) { |
| return true; |
| } |
| |
| constexpr size_t crashpad_info_min_size = |
| offsetof(decltype(crashpad_info_), reserved); |
| size_t remaining_data_size = stream_it->second->DataSize; |
| if (remaining_data_size < crashpad_info_min_size) { |
| LOG(ERROR) << "crashpad_info size mismatch"; |
| return false; |
| } |
| |
| if (!file_reader_->SeekSet(stream_it->second->Rva)) { |
| return false; |
| } |
| |
| if (!file_reader_->ReadExactly(&crashpad_info_, crashpad_info_min_size)) { |
| return false; |
| } |
| remaining_data_size -= crashpad_info_min_size; |
| |
| // Read `reserved` if available. |
| size_t crashpad_reserved_size = sizeof(crashpad_info_.reserved); |
| if (remaining_data_size >= crashpad_reserved_size) { |
| if (!file_reader_->ReadExactly(&crashpad_info_.reserved, |
| crashpad_reserved_size)) { |
| return false; |
| } |
| remaining_data_size -= crashpad_reserved_size; |
| } else { |
| crashpad_info_.reserved = 0; |
| } |
| |
| // Read `address_mask` if available. |
| size_t crashpad_address_mask_size = sizeof(crashpad_info_.address_mask); |
| if (remaining_data_size >= crashpad_address_mask_size) { |
| if (!file_reader_->ReadExactly(&crashpad_info_.address_mask, |
| crashpad_address_mask_size)) { |
| return false; |
| } |
| remaining_data_size -= crashpad_address_mask_size; |
| } else { |
| crashpad_info_.address_mask = 0; |
| } |
| |
| if (crashpad_info_.version != MinidumpCrashpadInfo::kVersion) { |
| LOG(ERROR) << "crashpad_info version mismatch"; |
| return false; |
| } |
| |
| return internal::ReadMinidumpSimpleStringDictionary( |
| file_reader_, |
| crashpad_info_.simple_annotations, |
| &annotations_simple_map_); |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeMiscInfo() { |
| const auto& stream_it = stream_map_.find(kMinidumpStreamTypeMiscInfo); |
| if (stream_it == stream_map_.end()) { |
| return true; |
| } |
| |
| if (!file_reader_->SeekSet(stream_it->second->Rva)) { |
| return false; |
| } |
| |
| const size_t size = stream_it->second->DataSize; |
| if (size != sizeof(MINIDUMP_MISC_INFO_5) && |
| size != sizeof(MINIDUMP_MISC_INFO_4) && |
| size != sizeof(MINIDUMP_MISC_INFO_3) && |
| size != sizeof(MINIDUMP_MISC_INFO_2) && |
| size != sizeof(MINIDUMP_MISC_INFO)) { |
| LOG(ERROR) << "misc_info size mismatch"; |
| return false; |
| } |
| |
| MINIDUMP_MISC_INFO_5 info; |
| if (!file_reader_->ReadExactly(&info, size)) { |
| return false; |
| } |
| |
| switch (stream_it->second->DataSize) { |
| case sizeof(MINIDUMP_MISC_INFO_5): |
| case sizeof(MINIDUMP_MISC_INFO_4): |
| #if defined(WCHAR_T_IS_16_BIT) |
| full_version_ = base::WideToUTF8(info.BuildString); |
| #else |
| full_version_ = base::UTF16ToUTF8(info.BuildString); |
| #endif |
| full_version_ = full_version_.substr(0, full_version_.find(';')); |
| [[fallthrough]]; |
| case sizeof(MINIDUMP_MISC_INFO_3): |
| case sizeof(MINIDUMP_MISC_INFO_2): |
| case sizeof(MINIDUMP_MISC_INFO): |
| // TODO(jperaza): Save the remaining misc info. |
| // https://crashpad.chromium.org/bug/10 |
| process_id_ = info.ProcessId; |
| create_time_ = info.ProcessCreateTime; |
| user_time_ = info.ProcessUserTime; |
| kernel_time_ = info.ProcessKernelTime; |
| } |
| |
| return true; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeModules() { |
| const auto& stream_it = stream_map_.find(kMinidumpStreamTypeModuleList); |
| if (stream_it == stream_map_.end()) { |
| return true; |
| } |
| |
| std::map<uint32_t, MINIDUMP_LOCATION_DESCRIPTOR> module_crashpad_info_links; |
| if (!InitializeModulesCrashpadInfo(&module_crashpad_info_links)) { |
| return false; |
| } |
| |
| if (stream_it->second->DataSize < sizeof(MINIDUMP_MODULE_LIST)) { |
| LOG(ERROR) << "module_list size mismatch"; |
| return false; |
| } |
| |
| if (!file_reader_->SeekSet(stream_it->second->Rva)) { |
| return false; |
| } |
| |
| uint32_t module_count; |
| if (!file_reader_->ReadExactly(&module_count, sizeof(module_count))) { |
| return false; |
| } |
| |
| if (sizeof(MINIDUMP_MODULE_LIST) + module_count * sizeof(MINIDUMP_MODULE) != |
| stream_it->second->DataSize) { |
| LOG(ERROR) << "module_list size mismatch"; |
| return false; |
| } |
| |
| for (uint32_t module_index = 0; module_index < module_count; ++module_index) { |
| const RVA module_rva = stream_it->second->Rva + sizeof(module_count) + |
| module_index * sizeof(MINIDUMP_MODULE); |
| |
| const auto& module_crashpad_info_it = |
| module_crashpad_info_links.find(module_index); |
| const MINIDUMP_LOCATION_DESCRIPTOR* module_crashpad_info_location = |
| module_crashpad_info_it != module_crashpad_info_links.end() |
| ? &module_crashpad_info_it->second |
| : nullptr; |
| |
| auto module = std::make_unique<internal::ModuleSnapshotMinidump>(); |
| if (!module->Initialize( |
| file_reader_, module_rva, module_crashpad_info_location)) { |
| return false; |
| } |
| |
| modules_.push_back(std::move(module)); |
| } |
| |
| return true; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeModulesCrashpadInfo( |
| std::map<uint32_t, MINIDUMP_LOCATION_DESCRIPTOR>* |
| module_crashpad_info_links) { |
| module_crashpad_info_links->clear(); |
| |
| if (crashpad_info_.version != MinidumpCrashpadInfo::kVersion) { |
| return false; |
| } |
| |
| if (crashpad_info_.module_list.Rva == 0) { |
| return true; |
| } |
| |
| if (crashpad_info_.module_list.DataSize < |
| sizeof(MinidumpModuleCrashpadInfoList)) { |
| LOG(ERROR) << "module_crashpad_info_list size mismatch"; |
| return false; |
| } |
| |
| if (!file_reader_->SeekSet(crashpad_info_.module_list.Rva)) { |
| return false; |
| } |
| |
| uint32_t crashpad_module_count; |
| if (!file_reader_->ReadExactly(&crashpad_module_count, |
| sizeof(crashpad_module_count))) { |
| return false; |
| } |
| |
| if (crashpad_info_.module_list.DataSize != |
| sizeof(MinidumpModuleCrashpadInfoList) + |
| crashpad_module_count * sizeof(MinidumpModuleCrashpadInfoLink)) { |
| LOG(ERROR) << "module_crashpad_info_list size mismatch"; |
| return false; |
| } |
| |
| std::unique_ptr<MinidumpModuleCrashpadInfoLink[]> minidump_links( |
| new MinidumpModuleCrashpadInfoLink[crashpad_module_count]); |
| if (!file_reader_->ReadExactly( |
| &minidump_links[0], |
| crashpad_module_count * sizeof(MinidumpModuleCrashpadInfoLink))) { |
| return false; |
| } |
| |
| for (uint32_t crashpad_module_index = 0; |
| crashpad_module_index < crashpad_module_count; |
| ++crashpad_module_index) { |
| const MinidumpModuleCrashpadInfoLink& minidump_link = |
| minidump_links[crashpad_module_index]; |
| if (!module_crashpad_info_links |
| ->insert(std::make_pair(minidump_link.minidump_module_list_index, |
| minidump_link.location)) |
| .second) { |
| LOG(WARNING) |
| << "duplicate module_crashpad_info_list minidump_module_list_index " |
| << minidump_link.minidump_module_list_index; |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeMemoryInfo() { |
| const auto& stream_it = stream_map_.find(kMinidumpStreamTypeMemoryInfoList); |
| if (stream_it == stream_map_.end()) { |
| return true; |
| } |
| |
| if (stream_it->second->DataSize < sizeof(MINIDUMP_MEMORY_INFO_LIST)) { |
| LOG(ERROR) << "memory_info_list size mismatch"; |
| return false; |
| } |
| |
| if (!file_reader_->SeekSet(stream_it->second->Rva)) { |
| return false; |
| } |
| |
| MINIDUMP_MEMORY_INFO_LIST list; |
| |
| if (!file_reader_->ReadExactly(&list, sizeof(list))) { |
| return false; |
| } |
| |
| if (list.SizeOfHeader != sizeof(list)) { |
| return false; |
| } |
| |
| if (list.SizeOfEntry != sizeof(MINIDUMP_MEMORY_INFO)) { |
| return false; |
| } |
| |
| if (sizeof(MINIDUMP_MEMORY_INFO_LIST) + |
| list.NumberOfEntries * list.SizeOfEntry != |
| stream_it->second->DataSize) { |
| LOG(ERROR) << "memory_info_list size mismatch"; |
| return false; |
| } |
| |
| for (uint32_t i = 0; i < list.NumberOfEntries; i++) { |
| MINIDUMP_MEMORY_INFO info; |
| |
| if (!file_reader_->ReadExactly(&info, sizeof(info))) { |
| return false; |
| } |
| |
| mem_regions_.emplace_back( |
| std::make_unique<internal::MemoryMapRegionSnapshotMinidump>(info)); |
| mem_regions_exposed_.emplace_back(mem_regions_.back().get()); |
| } |
| |
| return true; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeExtraMemory() { |
| const auto& stream_it = stream_map_.find(kMinidumpStreamTypeMemoryList); |
| if (stream_it == stream_map_.end()) { |
| return true; |
| } |
| |
| if (stream_it->second->DataSize < sizeof(MINIDUMP_MEMORY_LIST)) { |
| LOG(ERROR) << "memory_list size mismatch"; |
| return false; |
| } |
| |
| if (!file_reader_->SeekSet(stream_it->second->Rva)) { |
| return false; |
| } |
| |
| // MSVC won't let us stack-allocate a MINIDUMP_MEMORY_LIST because of its |
| // trailing zero-element array. Luckily we're only interested in its other |
| // field anyway: a uint32_t indicating the number of memory descriptors that |
| // follow. |
| static_assert( |
| sizeof(MINIDUMP_MEMORY_LIST) == 4, |
| "MINIDUMP_MEMORY_LIST's only actual field should be an uint32_t"); |
| uint32_t num_ranges; |
| if (!file_reader_->ReadExactly(&num_ranges, sizeof(num_ranges))) { |
| return false; |
| } |
| |
| // We have to manually keep track of the locations of the entries in the |
| // contiguous list of MINIDUMP_MEMORY_DESCRIPTORs, because the Initialize() |
| // function jumps around the file to find the contents of each snapshot. |
| FileOffset location = file_reader_->SeekGet(); |
| for (uint32_t i = 0; i < num_ranges; i++) { |
| extra_memory_.emplace_back( |
| std::make_unique<internal::MemorySnapshotMinidump>()); |
| if (!extra_memory_.back()->Initialize(file_reader_, |
| static_cast<RVA>(location))) { |
| return false; |
| } |
| location += sizeof(MINIDUMP_MEMORY_DESCRIPTOR); |
| } |
| |
| return true; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeThreads() { |
| const auto& stream_it = stream_map_.find(kMinidumpStreamTypeThreadList); |
| if (stream_it == stream_map_.end()) { |
| return true; |
| } |
| |
| if (stream_it->second->DataSize < sizeof(MINIDUMP_THREAD_LIST)) { |
| LOG(ERROR) << "thread_list size mismatch"; |
| return false; |
| } |
| |
| if (!file_reader_->SeekSet(stream_it->second->Rva)) { |
| return false; |
| } |
| |
| uint32_t thread_count; |
| if (!file_reader_->ReadExactly(&thread_count, sizeof(thread_count))) { |
| return false; |
| } |
| |
| if (sizeof(MINIDUMP_THREAD_LIST) + thread_count * sizeof(MINIDUMP_THREAD) != |
| stream_it->second->DataSize) { |
| LOG(ERROR) << "thread_list size mismatch"; |
| return false; |
| } |
| |
| if (!InitializeThreadNames()) { |
| return false; |
| } |
| |
| for (uint32_t thread_index = 0; thread_index < thread_count; ++thread_index) { |
| const RVA thread_rva = stream_it->second->Rva + sizeof(thread_count) + |
| thread_index * sizeof(MINIDUMP_THREAD); |
| |
| auto thread = std::make_unique<internal::ThreadSnapshotMinidump>(); |
| if (!thread->Initialize(file_reader_, thread_rva, arch_, thread_names_)) { |
| return false; |
| } |
| |
| threads_.push_back(std::move(thread)); |
| } |
| |
| return true; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeThreadNames() { |
| const auto& stream_it = stream_map_.find(kMinidumpStreamTypeThreadNameList); |
| if (stream_it == stream_map_.end()) { |
| return true; |
| } |
| |
| if (stream_it->second->DataSize < sizeof(MINIDUMP_THREAD_NAME_LIST)) { |
| LOG(ERROR) << "thread_name_list size mismatch"; |
| return false; |
| } |
| |
| if (!file_reader_->SeekSet(stream_it->second->Rva)) { |
| return false; |
| } |
| |
| uint32_t thread_name_count; |
| if (!file_reader_->ReadExactly(&thread_name_count, |
| sizeof(thread_name_count))) { |
| return false; |
| } |
| |
| if (sizeof(MINIDUMP_THREAD_NAME_LIST) + |
| thread_name_count * sizeof(MINIDUMP_THREAD_NAME) != |
| stream_it->second->DataSize) { |
| LOG(ERROR) << "thread_name_list size mismatch"; |
| return false; |
| } |
| |
| for (uint32_t thread_name_index = 0; thread_name_index < thread_name_count; |
| ++thread_name_index) { |
| const RVA thread_name_rva = |
| stream_it->second->Rva + sizeof(thread_name_count) + |
| thread_name_index * sizeof(MINIDUMP_THREAD_NAME); |
| if (!file_reader_->SeekSet(thread_name_rva)) { |
| return false; |
| } |
| MINIDUMP_THREAD_NAME minidump_thread_name; |
| if (!file_reader_->ReadExactly(&minidump_thread_name, |
| sizeof(minidump_thread_name))) { |
| return false; |
| } |
| std::string name; |
| if (!internal::ReadMinidumpUTF16String( |
| file_reader_, minidump_thread_name.RvaOfThreadName, &name)) { |
| return false; |
| } |
| |
| // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36566 |
| const uint32_t thread_id = minidump_thread_name.ThreadId; |
| thread_names_.emplace(thread_id, std::move(name)); |
| } |
| |
| return true; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeSystemSnapshot() { |
| const auto& stream_it = stream_map_.find(kMinidumpStreamTypeSystemInfo); |
| if (stream_it == stream_map_.end()) { |
| return true; |
| } |
| |
| if (stream_it->second->DataSize < sizeof(MINIDUMP_SYSTEM_INFO)) { |
| LOG(ERROR) << "system info size mismatch"; |
| return false; |
| } |
| |
| if (!system_snapshot_.Initialize( |
| file_reader_, stream_it->second->Rva, full_version_)) { |
| return false; |
| } |
| |
| arch_ = system_snapshot_.GetCPUArchitecture(); |
| return true; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeCustomMinidumpStreams() { |
| for (size_t i = 0; i < stream_directory_.size(); i++) { |
| const auto& stream = stream_directory_[i]; |
| |
| // Filter out reserved minidump and crashpad streams. |
| const uint32_t stream_type = stream.StreamType; |
| if (stream_type <= |
| MinidumpStreamType::kMinidumpStreamTypeLastReservedStream || |
| (stream_type >= MinidumpStreamType::kMinidumpStreamTypeCrashpadInfo && |
| stream_type <= MinidumpStreamType:: |
| kMinidumpStreamTypeCrashpadLastReservedStream)) { |
| continue; |
| } |
| |
| std::vector<uint8_t> data(stream.Location.DataSize); |
| if (!file_reader_->SeekSet(stream.Location.Rva) || |
| !file_reader_->ReadExactly(data.data(), data.size())) { |
| LOG(ERROR) << "Failed to read stream with ID 0x" << std::hex |
| << stream_type << std::dec << " at index " << i; |
| return false; |
| } |
| |
| custom_streams_.push_back( |
| std::make_unique<MinidumpStream>(stream_type, std::move(data))); |
| } |
| |
| return true; |
| } |
| |
| bool ProcessSnapshotMinidump::InitializeExceptionSnapshot() { |
| const auto& stream_it = stream_map_.find(kMinidumpStreamTypeException); |
| if (stream_it == stream_map_.end()) { |
| return true; |
| } |
| |
| if (stream_it->second->DataSize < sizeof(MINIDUMP_EXCEPTION_STREAM)) { |
| LOG(ERROR) << "system info size mismatch"; |
| return false; |
| } |
| |
| if (!exception_snapshot_.Initialize( |
| file_reader_, arch_, stream_it->second->Rva)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| } // namespace crashpad |