diff --git a/llvm/include/llvm/BinaryFormat/Minidump.h b/llvm/include/llvm/BinaryFormat/Minidump.h --- a/llvm/include/llvm/BinaryFormat/Minidump.h +++ b/llvm/include/llvm/BinaryFormat/Minidump.h @@ -72,6 +72,12 @@ 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 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/llvm/include/llvm/ObjectYAML/MinidumpYAML.h b/llvm/include/llvm/ObjectYAML/MinidumpYAML.h --- a/llvm/include/llvm/ObjectYAML/MinidumpYAML.h +++ b/llvm/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 { + MemoryInfoList, MemoryList, ModuleList, RawContent, @@ -102,6 +103,26 @@ 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 @@ 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 @@ } // 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_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(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/llvm/lib/ObjectYAML/MinidumpEmitter.cpp b/llvm/lib/ObjectYAML/MinidumpEmitter.cpp --- a/llvm/lib/ObjectYAML/MinidumpEmitter.cpp +++ b/llvm/lib/ObjectYAML/MinidumpEmitter.cpp @@ -158,6 +158,14 @@ 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/llvm/lib/ObjectYAML/MinidumpYAML.cpp b/llvm/lib/ObjectYAML/MinidumpYAML.cpp --- a/llvm/lib/ObjectYAML/MinidumpYAML.cpp +++ b/llvm/lib/ObjectYAML/MinidumpYAML.cpp @@ -69,6 +69,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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/llvm/test/tools/obj2yaml/basic-minidump.yaml b/llvm/test/tools/obj2yaml/basic-minidump.yaml --- a/llvm/test/tools/obj2yaml/basic-minidump.yaml +++ b/llvm/test/tools/obj2yaml/basic-minidump.yaml @@ -55,6 +55,27 @@ 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 @@ # 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: ...