diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index a9bd0f04..12738434 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -16,11 +16,29 @@ #include +#include "snapshot/memory_map_region_snapshot.h" #include "snapshot/minidump/minidump_simple_string_dictionary_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_(), @@ -90,6 +108,7 @@ bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { !InitializeMiscInfo() || !InitializeModules() || !InitializeSystemSnapshot() || + !InitializeMemoryInfo() || !InitializeThreads()) { return false; } @@ -194,8 +213,7 @@ const ExceptionSnapshot* ProcessSnapshotMinidump::Exception() const { std::vector ProcessSnapshotMinidump::MemoryMap() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); - NOTREACHED(); // https://crashpad.chromium.org/bug/10 - return std::vector(); + return mem_regions_exposed_; } std::vector ProcessSnapshotMinidump::Handles() const { @@ -396,6 +414,56 @@ bool ProcessSnapshotMinidump::InitializeModulesCrashpadInfo( 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(info)); + mem_regions_exposed_.emplace_back(mem_regions_.back().get()); + } + + return true; +} + bool ProcessSnapshotMinidump::InitializeThreads() { const auto& stream_it = stream_map_.find(kMinidumpStreamTypeThreadList); if (stream_it == stream_map_.end()) { diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index 2ef23a68..3f256184 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -43,6 +43,10 @@ namespace crashpad { +namespace internal { +class MemoryMapRegionSnapshotMinidump; +} // namespace internal + //! \brief A ProcessSnapshot based on a minidump file. class ProcessSnapshotMinidump final : public ProcessSnapshot { public: @@ -91,6 +95,10 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { // Initialize(). bool InitializeThreads(); + // Initializes data carried in a MINIDUMP_MEMORY_INFO_LIST stream on behalf of + // Initialize(). + bool InitializeMemoryInfo(); + // Initializes data carried in a MINIDUMP_SYSTEM_INFO stream on behalf of // Initialize(). bool InitializeSystemSnapshot(); @@ -112,6 +120,9 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector> modules_; std::vector> threads_; std::vector unloaded_modules_; + std::vector> + mem_regions_; + std::vector mem_regions_exposed_; MinidumpCrashpadInfo crashpad_info_; internal::SystemSnapshotMinidump system_snapshot_; CPUArchitecture arch_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index 876356c8..ceae1c72 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -24,6 +24,7 @@ #include "gtest/gtest.h" #include "minidump/minidump_context.h" #include "snapshot/minidump/minidump_annotation_reader.h" +#include "snapshot/memory_map_region_snapshot.h" #include "snapshot/module_snapshot.h" #include "util/file/string_file.h" #include "util/misc/pdb_structures.h" @@ -968,6 +969,76 @@ TEST(ProcessSnapshotMinidump, ThreadContextX86_64) { } } +TEST(ProcessSnapshotMinidump, MemoryMap) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + MINIDUMP_MEMORY_INFO minidump_memory_info_1 = {}; + MINIDUMP_MEMORY_INFO minidump_memory_info_2 = {}; + uint32_t minidump_memory_info_count = 2; + + minidump_memory_info_1.BaseAddress = 1; + minidump_memory_info_1.AllocationBase = 2; + minidump_memory_info_1.AllocationProtect = 3; + minidump_memory_info_1.RegionSize = 4; + minidump_memory_info_1.State = 5; + minidump_memory_info_1.Protect = 6; + minidump_memory_info_1.Type = 6; + + minidump_memory_info_2.BaseAddress = 7; + minidump_memory_info_2.AllocationBase = 8; + minidump_memory_info_2.AllocationProtect = 9; + minidump_memory_info_2.RegionSize = 10; + minidump_memory_info_2.State = 11; + minidump_memory_info_2.Protect = 12; + minidump_memory_info_2.Type = 13; + + MINIDUMP_MEMORY_INFO_LIST minidump_memory_info_list = {}; + + minidump_memory_info_list.SizeOfHeader = sizeof(minidump_memory_info_list); + minidump_memory_info_list.SizeOfEntry = sizeof(MINIDUMP_MEMORY_INFO); + minidump_memory_info_list.NumberOfEntries = minidump_memory_info_count; + + MINIDUMP_DIRECTORY minidump_memory_info_list_directory = {}; + minidump_memory_info_list_directory.StreamType = + kMinidumpStreamTypeMemoryInfoList; + minidump_memory_info_list_directory.Location.DataSize = + sizeof(minidump_memory_info_list) + + minidump_memory_info_count * sizeof(MINIDUMP_MEMORY_INFO); + minidump_memory_info_list_directory.Location.Rva = + static_cast(string_file.SeekGet()); + + EXPECT_TRUE(string_file.Write(&minidump_memory_info_list, + sizeof(minidump_memory_info_list))); + EXPECT_TRUE(string_file.Write(&minidump_memory_info_1, + sizeof(minidump_memory_info_1))); + EXPECT_TRUE(string_file.Write(&minidump_memory_info_2, + sizeof(minidump_memory_info_2))); + + header.StreamDirectoryRva = static_cast(string_file.SeekGet()); + EXPECT_TRUE(string_file.Write(&minidump_memory_info_list_directory, + sizeof(minidump_memory_info_list_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + EXPECT_TRUE(string_file.SeekSet(0)); + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_TRUE(process_snapshot.Initialize(&string_file)); + + std::vector map = + process_snapshot.MemoryMap(); + ASSERT_EQ(map.size(), minidump_memory_info_count); + EXPECT_EQ(memcmp(&map[0]->AsMinidumpMemoryInfo(), &minidump_memory_info_1, + sizeof(minidump_memory_info_1)), 0); + EXPECT_EQ(memcmp(&map[1]->AsMinidumpMemoryInfo(), &minidump_memory_info_2, + sizeof(minidump_memory_info_2)), 0); +} + } // namespace } // namespace test } // namespace crashpad