From 146f4968ec0ed2831535fc5162befaeef3cf1796 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Thu, 10 Oct 2019 13:05:46 +0000 Subject: [PATCH] MinidumpYAML: Add support for the memory info list stream Summary: The implementation is fairly straight-forward and uses the same patterns as the existing streams. The yaml form does not attempt to preserve the data in the "gaps" that can be created by setting a larger-than-required header or entry size in the stream header, because the existing consumer (lldb) does not make use of the information in the gap in any way, and attempting to preserve that would make the implementation more complicated. Reviewers: amccarth, jhenderson, clayborg Subscribers: llvm-commits, lldb-commits, markmentovai, zturner, JosephTremoulet Tags: #llvm Differential Revision: https://reviews.llvm.org/D68645 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374337 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/BinaryFormat/Minidump.h | 8 ++++ include/llvm/ObjectYAML/MinidumpYAML.h | 37 +++++++++++++++--- lib/ObjectYAML/MinidumpEmitter.cpp | 8 ++++ lib/ObjectYAML/MinidumpYAML.cpp | 51 +++++++++++++++++++++++++ test/tools/obj2yaml/basic-minidump.yaml | 42 ++++++++++++++++++++ 5 files changed, 141 insertions(+), 5 deletions(-) diff --git a/include/llvm/BinaryFormat/Minidump.h b/include/llvm/BinaryFormat/Minidump.h index 93df467cd82..0ecd341da8c 100644 --- a/include/llvm/BinaryFormat/Minidump.h +++ b/include/llvm/BinaryFormat/Minidump.h @@ -72,6 +72,12 @@ struct MemoryInfoListHeader { support::ulittle32_t SizeOfHeader; support::ulittle32_t SizeOfEntry; support::ulittle64_t NumberOfEntries; + + MemoryInfoListHeader() = default; + MemoryInfoListHeader(uint32_t SizeOfHeader, uint32_t SizeOfEntry, + uint64_t NumberOfEntries) + : SizeOfHeader(SizeOfHeader), SizeOfEntry(SizeOfEntry), + NumberOfEntries(NumberOfEntries) {} }; static_assert(sizeof(MemoryInfoListHeader) == 16, ""); @@ -84,11 +90,13 @@ enum class MemoryProtection : uint32_t { enum class MemoryState : uint32_t { #define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME) NAME = CODE, #include "llvm/BinaryFormat/MinidumpConstants.def" + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/0xffffffffu), }; enum class MemoryType : uint32_t { #define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME) NAME = CODE, #include "llvm/BinaryFormat/MinidumpConstants.def" + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/0xffffffffu), }; struct MemoryInfo { diff --git a/include/llvm/ObjectYAML/MinidumpYAML.h b/include/llvm/ObjectYAML/MinidumpYAML.h index b4163e483e8..54be8886c64 100644 --- a/include/llvm/ObjectYAML/MinidumpYAML.h +++ b/include/llvm/ObjectYAML/MinidumpYAML.h @@ -26,6 +26,7 @@ namespace MinidumpYAML { /// from Types to Kinds is fixed and given by the static getKind function. struct Stream { enum class StreamKind { + MemoryInfoList, MemoryList, ModuleList, RawContent, @@ -102,6 +103,26 @@ using ModuleListStream = detail::ListStream; using ThreadListStream = detail::ListStream; using MemoryListStream = detail::ListStream; +/// A structure containing the list of MemoryInfo entries comprising a +/// MemoryInfoList stream. +struct MemoryInfoListStream : public Stream { + std::vector Infos; + + MemoryInfoListStream() + : Stream(StreamKind::MemoryInfoList, + minidump::StreamType::MemoryInfoList) {} + + explicit MemoryInfoListStream( + iterator_range Range) + : Stream(StreamKind::MemoryInfoList, + minidump::StreamType::MemoryInfoList), + Infos(Range.begin(), Range.end()) {} + + static bool classof(const Stream *S) { + return S->Kind == StreamKind::MemoryInfoList; + } +}; + /// A minidump stream represented as a sequence of hex bytes. This is used as a /// fallback when no other stream kind is suitable. struct RawContentStream : public Stream { @@ -122,16 +143,16 @@ struct SystemInfoStream : public Stream { minidump::SystemInfo Info; std::string CSDVersion; - explicit SystemInfoStream(const minidump::SystemInfo &Info, - std::string CSDVersion) - : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo), - Info(Info), CSDVersion(std::move(CSDVersion)) {} - SystemInfoStream() : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo) { memset(&Info, 0, sizeof(Info)); } + explicit SystemInfoStream(const minidump::SystemInfo &Info, + std::string CSDVersion) + : Stream(StreamKind::SystemInfo, minidump::StreamType::SystemInfo), + Info(Info), CSDVersion(std::move(CSDVersion)) {} + static bool classof(const Stream *S) { return S->Kind == StreamKind::SystemInfo; } @@ -207,6 +228,10 @@ template <> struct MappingContextTraits { } // namespace llvm +LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryProtection) +LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryState) +LLVM_YAML_DECLARE_BITSET_TRAITS(llvm::minidump::MemoryType) + LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::ProcessorArchitecture) LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::OSPlatform) LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::StreamType) @@ -214,6 +239,7 @@ LLVM_YAML_DECLARE_ENUM_TRAITS(llvm::minidump::StreamType) LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::ArmInfo) LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::OtherInfo) LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info) +LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::MemoryInfo) LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo) LLVM_YAML_DECLARE_MAPPING_TRAITS( @@ -227,6 +253,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr) 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) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::minidump::MemoryInfo) LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::MinidumpYAML::Object) diff --git a/lib/ObjectYAML/MinidumpEmitter.cpp b/lib/ObjectYAML/MinidumpEmitter.cpp index 31a839e524c..9029be80ad7 100644 --- a/lib/ObjectYAML/MinidumpEmitter.cpp +++ b/lib/ObjectYAML/MinidumpEmitter.cpp @@ -158,6 +158,14 @@ static Directory layout(BlobAllocator &File, Stream &S) { Result.Location.RVA = File.tell(); Optional DataEnd; switch (S.Kind) { + case Stream::StreamKind::MemoryInfoList: { + MemoryInfoListStream &InfoList = cast(S); + File.allocateNewObject( + sizeof(minidump::MemoryInfoListHeader), sizeof(minidump::MemoryInfo), + InfoList.Infos.size()); + File.allocateArray(makeArrayRef(InfoList.Infos)); + break; + } case Stream::StreamKind::MemoryList: DataEnd = layout(File, cast(S)); break; diff --git a/lib/ObjectYAML/MinidumpYAML.cpp b/lib/ObjectYAML/MinidumpYAML.cpp index acc36a95a29..b9d1ded1816 100644 --- a/lib/ObjectYAML/MinidumpYAML.cpp +++ b/lib/ObjectYAML/MinidumpYAML.cpp @@ -69,6 +69,8 @@ Stream::~Stream() = default; Stream::StreamKind Stream::getKind(StreamType Type) { switch (Type) { + case StreamType::MemoryInfoList: + return StreamKind::MemoryInfoList; case StreamType::MemoryList: return StreamKind::MemoryList; case StreamType::ModuleList: @@ -93,6 +95,8 @@ Stream::StreamKind Stream::getKind(StreamType Type) { std::unique_ptr Stream::create(StreamType Type) { StreamKind Kind = getKind(Type); switch (Kind) { + case StreamKind::MemoryInfoList: + return std::make_unique(); case StreamKind::MemoryList: return std::make_unique(); case StreamKind::ModuleList: @@ -109,6 +113,25 @@ std::unique_ptr Stream::create(StreamType Type) { llvm_unreachable("Unhandled stream kind!"); } +void yaml::ScalarBitSetTraits::bitset( + IO &IO, MemoryProtection &Protect) { +#define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME) \ + IO.bitSetCase(Protect, #NATIVENAME, MemoryProtection::NAME); +#include "llvm/BinaryFormat/MinidumpConstants.def" +} + +void yaml::ScalarBitSetTraits::bitset(IO &IO, MemoryState &State) { +#define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME) \ + IO.bitSetCase(State, #NATIVENAME, MemoryState::NAME); +#include "llvm/BinaryFormat/MinidumpConstants.def" +} + +void yaml::ScalarBitSetTraits::bitset(IO &IO, MemoryType &Type) { +#define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME) \ + IO.bitSetCase(Type, #NATIVENAME, MemoryType::NAME); +#include "llvm/BinaryFormat/MinidumpConstants.def" +} + void yaml::ScalarEnumerationTraits::enumeration( IO &IO, ProcessorArchitecture &Arch) { #define HANDLE_MDMP_ARCH(CODE, NAME) \ @@ -215,6 +238,20 @@ void yaml::MappingTraits::mapping(IO &IO, mapOptionalHex(IO, "AMD Extended Features", Info.AMDExtendedFeatures, 0); } +void yaml::MappingTraits::mapping(IO &IO, MemoryInfo &Info) { + mapRequiredHex(IO, "Base Address", Info.BaseAddress); + mapOptionalHex(IO, "Allocation Base", Info.AllocationBase, Info.BaseAddress); + mapRequiredAs(IO, "Allocation Protect", + Info.AllocationProtect); + mapOptionalHex(IO, "Reserved0", Info.Reserved0, 0); + mapRequiredHex(IO, "Region Size", Info.RegionSize); + mapRequiredAs(IO, "State", Info.State); + mapOptionalAs(IO, "Protect", Info.Protect, + Info.AllocationProtect); + mapRequiredAs(IO, "Type", Info.Type); + mapOptionalHex(IO, "Reserved1", Info.Reserved1, 0); +} + void yaml::MappingTraits::mapping(IO &IO, VSFixedFileInfo &Info) { mapOptionalHex(IO, "Signature", Info.Signature, 0); @@ -264,6 +301,10 @@ void yaml::MappingTraits::mapping( IO, Range.Entry, Range.Content); } +static void streamMapping(yaml::IO &IO, MemoryInfoListStream &Stream) { + IO.mapRequired("Memory Ranges", Stream.Infos); +} + static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) { IO.mapRequired("Memory Ranges", Stream.Entries); } @@ -336,6 +377,9 @@ void yaml::MappingTraits>::mapping( if (!IO.outputting()) S = MinidumpYAML::Stream::create(Type); switch (S->Kind) { + case MinidumpYAML::Stream::StreamKind::MemoryInfoList: + streamMapping(IO, llvm::cast(*S)); + break; case MinidumpYAML::Stream::StreamKind::MemoryList: streamMapping(IO, llvm::cast(*S)); break; @@ -362,6 +406,7 @@ StringRef yaml::MappingTraits>::validate( switch (S->Kind) { case MinidumpYAML::Stream::StreamKind::RawContent: return streamValidate(cast(*S)); + case MinidumpYAML::Stream::StreamKind::MemoryInfoList: case MinidumpYAML::Stream::StreamKind::MemoryList: case MinidumpYAML::Stream::StreamKind::ModuleList: case MinidumpYAML::Stream::StreamKind::SystemInfo: @@ -384,6 +429,12 @@ Expected> Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) { StreamKind Kind = getKind(StreamDesc.Type); switch (Kind) { + case StreamKind::MemoryInfoList: { + if (auto ExpectedList = File.getMemoryInfoList()) + return std::make_unique(*ExpectedList); + else + return ExpectedList.takeError(); + } case StreamKind::MemoryList: { auto ExpectedList = File.getMemoryList(); if (!ExpectedList) diff --git a/test/tools/obj2yaml/basic-minidump.yaml b/test/tools/obj2yaml/basic-minidump.yaml index af08fe19bb7..e4955dbbf35 100644 --- a/test/tools/obj2yaml/basic-minidump.yaml +++ b/test/tools/obj2yaml/basic-minidump.yaml @@ -55,6 +55,27 @@ Streams: Memory Ranges: - Start of Memory Range: 0x7C7D7E7F80818283 Content: '8485868788' + - Type: MemoryInfoList + Memory Ranges: + - Base Address: 0x0000000000000000 + Allocation Protect: [ ] + Region Size: 0x0000000000010000 + State: [ MEM_FREE ] + Protect: [ PAGE_NO_ACCESS ] + Type: [ ] + - Base Address: 0x0000000000010000 + Allocation Protect: [ PAGE_READ_WRITE ] + Region Size: 0x0000000000010000 + State: [ MEM_COMMIT ] + Type: [ MEM_MAPPED ] + - Base Address: 0x0000000000020000 + Allocation Base: 0x0000000000000000 + Allocation Protect: [ PAGE_READ_WRITE, PAGE_WRITECOMBINE ] + Reserved0: 0xDEADBEEF + Region Size: 0x0000000000010000 + State: [ MEM_COMMIT, MEM_FREE ] + Type: [ MEM_PRIVATE, MEM_MAPPED ] + Reserved1: 0xBAADF00D ... # CHECK: --- !minidump @@ -112,4 +133,25 @@ Streams: # CHECK-NEXT: Memory Ranges: # CHECK-NEXT: - Start of Memory Range: 0x7C7D7E7F80818283 # CHECK-NEXT: Content: '8485868788' +# CHECK-NEXT: - Type: MemoryInfoList +# CHECK-NEXT: Memory Ranges: +# CHECK-NEXT: - Base Address: 0x0000000000000000 +# CHECK-NEXT: Allocation Protect: [ ] +# CHECK-NEXT: Region Size: 0x0000000000010000 +# CHECK-NEXT: State: [ MEM_FREE ] +# CHECK-NEXT: Protect: [ PAGE_NO_ACCESS ] +# CHECK-NEXT: Type: [ ] +# CHECK-NEXT: - Base Address: 0x0000000000010000 +# CHECK-NEXT: Allocation Protect: [ PAGE_READ_WRITE ] +# CHECK-NEXT: Region Size: 0x0000000000010000 +# CHECK-NEXT: State: [ MEM_COMMIT ] +# CHECK-NEXT: Type: [ MEM_MAPPED ] +# CHECK-NEXT: - Base Address: 0x0000000000020000 +# CHECK-NEXT: Allocation Base: 0x0000000000000000 +# CHECK-NEXT: Allocation Protect: [ PAGE_READ_WRITE, PAGE_WRITECOMBINE ] +# CHECK-NEXT: Reserved0: 0xDEADBEEF +# CHECK-NEXT: Region Size: 0x0000000000010000 +# CHECK-NEXT: State: [ MEM_COMMIT, MEM_FREE ] +# CHECK-NEXT: Type: [ MEM_PRIVATE, MEM_MAPPED ] +# CHECK-NEXT: Reserved1: 0xBAADF00D # CHECK-NEXT: ... -- 2.50.1