labath created this revision. labath added reviewers: amccarth, jhenderson, clayborg. Herald added a project: LLVM.
the stream format is exactly the same as for ThreadList and ModuleList streams, only the entry types are slightly different, so the changes in this patch are just straight-forward applications of established patterns. Repository: rL LLVM https://reviews.llvm.org/D61885 Files: include/llvm/Object/Minidump.h include/llvm/ObjectYAML/MinidumpYAML.h lib/Object/Minidump.cpp lib/ObjectYAML/MinidumpYAML.cpp test/tools/obj2yaml/basic-minidump.yaml unittests/Object/MinidumpTest.cpp
Index: unittests/Object/MinidumpTest.cpp =================================================================== --- unittests/Object/MinidumpTest.cpp +++ unittests/Object/MinidumpTest.cpp @@ -463,3 +463,51 @@ EXPECT_EQ(0x08070605u, T.Context.RVA); } } + +TEST(MinidumpFile, getMemoryList) { + std::vector<uint8_t> OneRange{ + // Header + 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version + 1, 0, 0, 0, // NumberOfStreams, + 32, 0, 0, 0, // StreamDirectoryRVA + 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp + 0, 0, 0, 0, 0, 0, 0, 0, // Flags + // Stream Directory + 5, 0, 0, 0, 20, 0, 0, 0, // Type, DataSize, + 44, 0, 0, 0, // RVA + // MemoryDescriptor + 1, 0, 0, 0, // NumberOfMemoryRanges + 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange + 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA + }; + // Same as before, but with a padded thread list. + std::vector<uint8_t> PaddedRange{ + // Header + 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version + 1, 0, 0, 0, // NumberOfStreams, + 32, 0, 0, 0, // StreamDirectoryRVA + 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp + 0, 0, 0, 0, 0, 0, 0, 0, // Flags + // Stream Directory + 5, 0, 0, 0, 24, 0, 0, 0, // Type, DataSize, + 44, 0, 0, 0, // RVA + // MemoryDescriptor + 1, 0, 0, 0, // NumberOfMemoryRanges + 0, 0, 0, 0, // Padding + 5, 6, 7, 8, 9, 0, 1, 2, // StartOfMemoryRange + 3, 4, 5, 6, 7, 8, 9, 0, // DataSize, RVA + }; + + for (ArrayRef<uint8_t> Data : {OneRange, PaddedRange}) { + auto ExpectedFile = create(Data); + ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); + const MinidumpFile &File = **ExpectedFile; + Expected<ArrayRef<MemoryDescriptor>> ExpectedRanges = File.getMemoryList(); + ASSERT_THAT_EXPECTED(ExpectedRanges, Succeeded()); + ASSERT_EQ(1u, ExpectedRanges->size()); + const MemoryDescriptor &MD = ExpectedRanges.get()[0]; + EXPECT_EQ(0x0201000908070605u, MD.StartOfMemoryRange); + EXPECT_EQ(0x06050403u, MD.Memory.DataSize); + EXPECT_EQ(0x00090807u, MD.Memory.RVA); + } +} Index: test/tools/obj2yaml/basic-minidump.yaml =================================================================== --- test/tools/obj2yaml/basic-minidump.yaml +++ test/tools/obj2yaml/basic-minidump.yaml @@ -51,6 +51,10 @@ Stack: Start of Memory Range: 0x6C6D6E6F70717273 Content: 7475767778797A7B + - Type: MemoryList + Memory Ranges: + - Start of Memory Range: 0x7C7D7E7F80818283 + Content: '8485868788' ... # CHECK: --- !minidump @@ -104,4 +108,8 @@ # CHECK-NEXT: Stack: # CHECK-NEXT: Start of Memory Range: 0x6C6D6E6F70717273 # CHECK-NEXT: Content: 7475767778797A7B +# CHECK-NEXT: - Type: MemoryList +# CHECK-NEXT: Memory Ranges: +# CHECK-NEXT: - Start of Memory Range: 0x7C7D7E7F80818283 +# CHECK-NEXT: Content: '8485868788' # CHECK-NEXT: ... Index: lib/ObjectYAML/MinidumpYAML.cpp =================================================================== --- lib/ObjectYAML/MinidumpYAML.cpp +++ lib/ObjectYAML/MinidumpYAML.cpp @@ -168,6 +168,8 @@ Stream::StreamKind Stream::getKind(StreamType Type) { switch (Type) { + case StreamType::MemoryList: + return StreamKind::MemoryList; case StreamType::ModuleList: return StreamKind::ModuleList; case StreamType::SystemInfo: @@ -190,6 +192,8 @@ std::unique_ptr<Stream> Stream::create(StreamType Type) { StreamKind Kind = getKind(Type); switch (Kind) { + case StreamKind::MemoryList: + return llvm::make_unique<MemoryListStream>(); case StreamKind::ModuleList: return llvm::make_unique<ModuleListStream>(); case StreamKind::RawContent: @@ -353,6 +357,16 @@ return ""; } +void yaml::MappingTraits<MemoryListStream::entry_type>::mapping( + IO &IO, MemoryListStream::entry_type &Range) { + MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping( + IO, Range.Entry, Range.Content); +} + +static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) { + IO.mapRequired("Memory Ranges", Stream.Entries); +} + static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) { IO.mapRequired("Modules", Stream.Entries); } @@ -421,6 +435,9 @@ if (!IO.outputting()) S = MinidumpYAML::Stream::create(Type); switch (S->Kind) { + case MinidumpYAML::Stream::StreamKind::MemoryList: + streamMapping(IO, llvm::cast<MemoryListStream>(*S)); + break; case MinidumpYAML::Stream::StreamKind::ModuleList: streamMapping(IO, llvm::cast<ModuleListStream>(*S)); break; @@ -444,6 +461,7 @@ switch (S->Kind) { case MinidumpYAML::Stream::StreamKind::RawContent: return streamValidate(cast<RawContentStream>(*S)); + case MinidumpYAML::Stream::StreamKind::MemoryList: case MinidumpYAML::Stream::StreamKind::ModuleList: case MinidumpYAML::Stream::StreamKind::SystemInfo: case MinidumpYAML::Stream::StreamKind::TextContent: @@ -466,6 +484,10 @@ support::ulittle32_t(File.allocateBytes(Data))}; } +static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) { + Range.Entry.Memory = layout(File, Range.Content); +} + static void layout(BlobAllocator &File, ModuleListStream::entry_type &M) { M.Entry.ModuleNameRVA = File.allocateString(M.Name); @@ -502,6 +524,9 @@ Result.Location.RVA = File.tell(); Optional<size_t> DataEnd; switch (S.Kind) { + case Stream::StreamKind::MemoryList: + DataEnd = layout(File, cast<MemoryListStream>(S)); + break; case Stream::StreamKind::ModuleList: DataEnd = layout(File, cast<ModuleListStream>(S)); break; @@ -566,6 +591,19 @@ Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) { StreamKind Kind = getKind(StreamDesc.Type); switch (Kind) { + case StreamKind::MemoryList: { + auto ExpectedList = File.getMemoryList(); + if (!ExpectedList) + return ExpectedList.takeError(); + std::vector<MemoryListStream::entry_type> Ranges; + for (const MemoryDescriptor &MD : *ExpectedList) { + auto ExpectedContent = File.getRawData(MD.Memory); + if (!ExpectedContent) + return ExpectedContent.takeError(); + Ranges.push_back({MD, *ExpectedContent}); + } + return llvm::make_unique<MemoryListStream>(std::move(Ranges)); + } case StreamKind::ModuleList: { auto ExpectedList = File.getModuleList(); if (!ExpectedList) Index: lib/Object/Minidump.cpp =================================================================== --- lib/Object/Minidump.cpp +++ lib/Object/Minidump.cpp @@ -78,6 +78,8 @@ MinidumpFile::getListStream(StreamType) const; template Expected<ArrayRef<Thread>> MinidumpFile::getListStream(StreamType) const; +template Expected<ArrayRef<MemoryDescriptor>> + MinidumpFile::getListStream(StreamType) const; Expected<ArrayRef<uint8_t>> MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) { Index: include/llvm/ObjectYAML/MinidumpYAML.h =================================================================== --- include/llvm/ObjectYAML/MinidumpYAML.h +++ include/llvm/ObjectYAML/MinidumpYAML.h @@ -26,6 +26,7 @@ /// from Types to Kinds is fixed and given by the static getKind function. struct Stream { enum class StreamKind { + MemoryList, ModuleList, RawContent, SystemInfo, @@ -86,10 +87,20 @@ yaml::BinaryRef Stack; yaml::BinaryRef Context; }; + +/// A structure containing all data describing a single memory region. +struct ParsedMemoryRange { + static constexpr Stream::StreamKind Kind = Stream::StreamKind::MemoryList; + static constexpr minidump::StreamType Type = minidump::StreamType::MemoryList; + + minidump::MemoryDescriptor Entry; + yaml::BinaryRef Content; +}; } // namespace detail using ModuleListStream = detail::ListStream<detail::ParsedModule>; using ThreadListStream = detail::ListStream<detail::ParsedThread>; +using MemoryListStream = detail::ListStream<detail::ParsedMemoryRange>; /// A minidump stream represented as a sequence of hex bytes. This is used as a /// fallback when no other stream kind is suitable. @@ -211,12 +222,15 @@ LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info) LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo) +LLVM_YAML_DECLARE_MAPPING_TRAITS( + llvm::MinidumpYAML::MemoryListStream::entry_type) LLVM_YAML_DECLARE_MAPPING_TRAITS( llvm::MinidumpYAML::ModuleListStream::entry_type) LLVM_YAML_DECLARE_MAPPING_TRAITS( llvm::MinidumpYAML::ThreadListStream::entry_type) LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MinidumpYAML::Stream>) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::MemoryListStream::entry_type) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::entry_type) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ThreadListStream::entry_type) Index: include/llvm/Object/Minidump.h =================================================================== --- include/llvm/Object/Minidump.h +++ include/llvm/Object/Minidump.h @@ -80,6 +80,16 @@ return getListStream<minidump::Thread>(minidump::StreamType::ThreadList); } + /// Returns the list of memory ranges embedded in the MemoryList stream. An + /// error is returned if the file does not contain this stream, or if the + /// stream is not large enough to contain the number of threads declared in + /// the stream header. The consistency of the Thread entries themselves is not + /// checked in any way. + Expected<ArrayRef<minidump::MemoryDescriptor>> getMemoryList() const { + return getListStream<minidump::MemoryDescriptor>( + minidump::StreamType::MemoryList); + } + private: static Error createError(StringRef Str) { return make_error<GenericBinaryError>(Str, object_error::parse_failed);
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits