10b57cec5SDimitry Andric //===- MinidumpYAML.cpp - Minidump YAMLIO implementation ------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/ObjectYAML/MinidumpYAML.h"
100b57cec5SDimitry Andric #include "llvm/Support/Allocator.h"
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric using namespace llvm;
130b57cec5SDimitry Andric using namespace llvm::MinidumpYAML;
140b57cec5SDimitry Andric using namespace llvm::minidump;
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric /// Perform an optional yaml-mapping of an endian-aware type EndianType. The
170b57cec5SDimitry Andric /// only purpose of this function is to avoid casting the Default value to the
180b57cec5SDimitry Andric /// endian type;
190b57cec5SDimitry Andric template <typename EndianType>
mapOptional(yaml::IO & IO,const char * Key,EndianType & Val,typename EndianType::value_type Default)200b57cec5SDimitry Andric static inline void mapOptional(yaml::IO &IO, const char *Key, EndianType &Val,
210b57cec5SDimitry Andric                                typename EndianType::value_type Default) {
220b57cec5SDimitry Andric   IO.mapOptional(Key, Val, EndianType(Default));
230b57cec5SDimitry Andric }
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric /// Yaml-map an endian-aware type EndianType as some other type MapType.
260b57cec5SDimitry Andric template <typename MapType, typename EndianType>
mapRequiredAs(yaml::IO & IO,const char * Key,EndianType & Val)270b57cec5SDimitry Andric static inline void mapRequiredAs(yaml::IO &IO, const char *Key,
280b57cec5SDimitry Andric                                  EndianType &Val) {
290b57cec5SDimitry Andric   MapType Mapped = static_cast<typename EndianType::value_type>(Val);
300b57cec5SDimitry Andric   IO.mapRequired(Key, Mapped);
310b57cec5SDimitry Andric   Val = static_cast<typename EndianType::value_type>(Mapped);
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric /// Perform an optional yaml-mapping of an endian-aware type EndianType as some
350b57cec5SDimitry Andric /// other type MapType.
360b57cec5SDimitry Andric template <typename MapType, typename EndianType>
mapOptionalAs(yaml::IO & IO,const char * Key,EndianType & Val,MapType Default)370b57cec5SDimitry Andric static inline void mapOptionalAs(yaml::IO &IO, const char *Key, EndianType &Val,
380b57cec5SDimitry Andric                                  MapType Default) {
390b57cec5SDimitry Andric   MapType Mapped = static_cast<typename EndianType::value_type>(Val);
400b57cec5SDimitry Andric   IO.mapOptional(Key, Mapped, Default);
410b57cec5SDimitry Andric   Val = static_cast<typename EndianType::value_type>(Mapped);
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric namespace {
450b57cec5SDimitry Andric /// Return the appropriate yaml Hex type for a given endian-aware type.
460b57cec5SDimitry Andric template <typename EndianType> struct HexType;
470b57cec5SDimitry Andric template <> struct HexType<support::ulittle16_t> { using type = yaml::Hex16; };
480b57cec5SDimitry Andric template <> struct HexType<support::ulittle32_t> { using type = yaml::Hex32; };
490b57cec5SDimitry Andric template <> struct HexType<support::ulittle64_t> { using type = yaml::Hex64; };
500b57cec5SDimitry Andric } // namespace
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric /// Yaml-map an endian-aware type as an appropriately-sized hex value.
530b57cec5SDimitry Andric template <typename EndianType>
mapRequiredHex(yaml::IO & IO,const char * Key,EndianType & Val)540b57cec5SDimitry Andric static inline void mapRequiredHex(yaml::IO &IO, const char *Key,
550b57cec5SDimitry Andric                                   EndianType &Val) {
560b57cec5SDimitry Andric   mapRequiredAs<typename HexType<EndianType>::type>(IO, Key, Val);
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric /// Perform an optional yaml-mapping of an endian-aware type as an
600b57cec5SDimitry Andric /// appropriately-sized hex value.
610b57cec5SDimitry Andric template <typename EndianType>
mapOptionalHex(yaml::IO & IO,const char * Key,EndianType & Val,typename EndianType::value_type Default)620b57cec5SDimitry Andric static inline void mapOptionalHex(yaml::IO &IO, const char *Key,
630b57cec5SDimitry Andric                                   EndianType &Val,
640b57cec5SDimitry Andric                                   typename EndianType::value_type Default) {
650b57cec5SDimitry Andric   mapOptionalAs<typename HexType<EndianType>::type>(IO, Key, Val, Default);
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric Stream::~Stream() = default;
690b57cec5SDimitry Andric 
getKind(StreamType Type)700b57cec5SDimitry Andric Stream::StreamKind Stream::getKind(StreamType Type) {
710b57cec5SDimitry Andric   switch (Type) {
728bcb0991SDimitry Andric   case StreamType::Exception:
738bcb0991SDimitry Andric     return StreamKind::Exception;
748bcb0991SDimitry Andric   case StreamType::MemoryInfoList:
758bcb0991SDimitry Andric     return StreamKind::MemoryInfoList;
760b57cec5SDimitry Andric   case StreamType::MemoryList:
770b57cec5SDimitry Andric     return StreamKind::MemoryList;
780b57cec5SDimitry Andric   case StreamType::ModuleList:
790b57cec5SDimitry Andric     return StreamKind::ModuleList;
800b57cec5SDimitry Andric   case StreamType::SystemInfo:
810b57cec5SDimitry Andric     return StreamKind::SystemInfo;
820b57cec5SDimitry Andric   case StreamType::LinuxCPUInfo:
830b57cec5SDimitry Andric   case StreamType::LinuxProcStatus:
840b57cec5SDimitry Andric   case StreamType::LinuxLSBRelease:
850b57cec5SDimitry Andric   case StreamType::LinuxCMDLine:
860b57cec5SDimitry Andric   case StreamType::LinuxMaps:
870b57cec5SDimitry Andric   case StreamType::LinuxProcStat:
880b57cec5SDimitry Andric   case StreamType::LinuxProcUptime:
890b57cec5SDimitry Andric     return StreamKind::TextContent;
900b57cec5SDimitry Andric   case StreamType::ThreadList:
910b57cec5SDimitry Andric     return StreamKind::ThreadList;
920b57cec5SDimitry Andric   default:
930b57cec5SDimitry Andric     return StreamKind::RawContent;
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
create(StreamType Type)970b57cec5SDimitry Andric std::unique_ptr<Stream> Stream::create(StreamType Type) {
980b57cec5SDimitry Andric   StreamKind Kind = getKind(Type);
990b57cec5SDimitry Andric   switch (Kind) {
1008bcb0991SDimitry Andric   case StreamKind::Exception:
1018bcb0991SDimitry Andric     return std::make_unique<ExceptionStream>();
1028bcb0991SDimitry Andric   case StreamKind::MemoryInfoList:
1038bcb0991SDimitry Andric     return std::make_unique<MemoryInfoListStream>();
1040b57cec5SDimitry Andric   case StreamKind::MemoryList:
1058bcb0991SDimitry Andric     return std::make_unique<MemoryListStream>();
1060b57cec5SDimitry Andric   case StreamKind::ModuleList:
1078bcb0991SDimitry Andric     return std::make_unique<ModuleListStream>();
1080b57cec5SDimitry Andric   case StreamKind::RawContent:
1098bcb0991SDimitry Andric     return std::make_unique<RawContentStream>(Type);
1100b57cec5SDimitry Andric   case StreamKind::SystemInfo:
1118bcb0991SDimitry Andric     return std::make_unique<SystemInfoStream>();
1120b57cec5SDimitry Andric   case StreamKind::TextContent:
1138bcb0991SDimitry Andric     return std::make_unique<TextContentStream>(Type);
1140b57cec5SDimitry Andric   case StreamKind::ThreadList:
1158bcb0991SDimitry Andric     return std::make_unique<ThreadListStream>();
1160b57cec5SDimitry Andric   }
1170b57cec5SDimitry Andric   llvm_unreachable("Unhandled stream kind!");
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric 
bitset(IO & IO,MemoryProtection & Protect)1208bcb0991SDimitry Andric void yaml::ScalarBitSetTraits<MemoryProtection>::bitset(
1218bcb0991SDimitry Andric     IO &IO, MemoryProtection &Protect) {
1228bcb0991SDimitry Andric #define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME)                            \
1238bcb0991SDimitry Andric   IO.bitSetCase(Protect, #NATIVENAME, MemoryProtection::NAME);
1248bcb0991SDimitry Andric #include "llvm/BinaryFormat/MinidumpConstants.def"
1258bcb0991SDimitry Andric }
1268bcb0991SDimitry Andric 
bitset(IO & IO,MemoryState & State)1278bcb0991SDimitry Andric void yaml::ScalarBitSetTraits<MemoryState>::bitset(IO &IO, MemoryState &State) {
1288bcb0991SDimitry Andric #define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME)                           \
1298bcb0991SDimitry Andric   IO.bitSetCase(State, #NATIVENAME, MemoryState::NAME);
1308bcb0991SDimitry Andric #include "llvm/BinaryFormat/MinidumpConstants.def"
1318bcb0991SDimitry Andric }
1328bcb0991SDimitry Andric 
bitset(IO & IO,MemoryType & Type)1338bcb0991SDimitry Andric void yaml::ScalarBitSetTraits<MemoryType>::bitset(IO &IO, MemoryType &Type) {
1348bcb0991SDimitry Andric #define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME)                            \
1358bcb0991SDimitry Andric   IO.bitSetCase(Type, #NATIVENAME, MemoryType::NAME);
1368bcb0991SDimitry Andric #include "llvm/BinaryFormat/MinidumpConstants.def"
1378bcb0991SDimitry Andric }
1388bcb0991SDimitry Andric 
enumeration(IO & IO,ProcessorArchitecture & Arch)1390b57cec5SDimitry Andric void yaml::ScalarEnumerationTraits<ProcessorArchitecture>::enumeration(
1400b57cec5SDimitry Andric     IO &IO, ProcessorArchitecture &Arch) {
1410b57cec5SDimitry Andric #define HANDLE_MDMP_ARCH(CODE, NAME)                                           \
1420b57cec5SDimitry Andric   IO.enumCase(Arch, #NAME, ProcessorArchitecture::NAME);
1430b57cec5SDimitry Andric #include "llvm/BinaryFormat/MinidumpConstants.def"
1440b57cec5SDimitry Andric   IO.enumFallback<Hex16>(Arch);
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
enumeration(IO & IO,OSPlatform & Plat)1470b57cec5SDimitry Andric void yaml::ScalarEnumerationTraits<OSPlatform>::enumeration(IO &IO,
1480b57cec5SDimitry Andric                                                             OSPlatform &Plat) {
1490b57cec5SDimitry Andric #define HANDLE_MDMP_PLATFORM(CODE, NAME)                                       \
1500b57cec5SDimitry Andric   IO.enumCase(Plat, #NAME, OSPlatform::NAME);
1510b57cec5SDimitry Andric #include "llvm/BinaryFormat/MinidumpConstants.def"
1520b57cec5SDimitry Andric   IO.enumFallback<Hex32>(Plat);
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric 
enumeration(IO & IO,StreamType & Type)1550b57cec5SDimitry Andric void yaml::ScalarEnumerationTraits<StreamType>::enumeration(IO &IO,
1560b57cec5SDimitry Andric                                                             StreamType &Type) {
1570b57cec5SDimitry Andric #define HANDLE_MDMP_STREAM_TYPE(CODE, NAME)                                    \
1580b57cec5SDimitry Andric   IO.enumCase(Type, #NAME, StreamType::NAME);
1590b57cec5SDimitry Andric #include "llvm/BinaryFormat/MinidumpConstants.def"
1600b57cec5SDimitry Andric   IO.enumFallback<Hex32>(Type);
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric 
mapping(IO & IO,CPUInfo::ArmInfo & Info)1630b57cec5SDimitry Andric void yaml::MappingTraits<CPUInfo::ArmInfo>::mapping(IO &IO,
1640b57cec5SDimitry Andric                                                     CPUInfo::ArmInfo &Info) {
1650b57cec5SDimitry Andric   mapRequiredHex(IO, "CPUID", Info.CPUID);
1660b57cec5SDimitry Andric   mapOptionalHex(IO, "ELF hwcaps", Info.ElfHWCaps, 0);
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric namespace {
1700b57cec5SDimitry Andric template <std::size_t N> struct FixedSizeHex {
FixedSizeHex__anon2018ce470211::FixedSizeHex1710b57cec5SDimitry Andric   FixedSizeHex(uint8_t (&Storage)[N]) : Storage(Storage) {}
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   uint8_t (&Storage)[N];
1740b57cec5SDimitry Andric };
1750b57cec5SDimitry Andric } // namespace
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric namespace llvm {
1780b57cec5SDimitry Andric namespace yaml {
1790b57cec5SDimitry Andric template <std::size_t N> struct ScalarTraits<FixedSizeHex<N>> {
outputllvm::yaml::ScalarTraits1800b57cec5SDimitry Andric   static void output(const FixedSizeHex<N> &Fixed, void *, raw_ostream &OS) {
181bdd1243dSDimitry Andric     OS << toHex(ArrayRef(Fixed.Storage));
1820b57cec5SDimitry Andric   }
1830b57cec5SDimitry Andric 
inputllvm::yaml::ScalarTraits1840b57cec5SDimitry Andric   static StringRef input(StringRef Scalar, void *, FixedSizeHex<N> &Fixed) {
1850b57cec5SDimitry Andric     if (!all_of(Scalar, isHexDigit))
1860b57cec5SDimitry Andric       return "Invalid hex digit in input";
1870b57cec5SDimitry Andric     if (Scalar.size() < 2 * N)
1880b57cec5SDimitry Andric       return "String too short";
1890b57cec5SDimitry Andric     if (Scalar.size() > 2 * N)
1900b57cec5SDimitry Andric       return "String too long";
1910b57cec5SDimitry Andric     copy(fromHex(Scalar), Fixed.Storage);
1920b57cec5SDimitry Andric     return "";
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric 
mustQuotellvm::yaml::ScalarTraits1950b57cec5SDimitry Andric   static QuotingType mustQuote(StringRef S) { return QuotingType::None; }
1960b57cec5SDimitry Andric };
1970b57cec5SDimitry Andric } // namespace yaml
1980b57cec5SDimitry Andric } // namespace llvm
mapping(IO & IO,CPUInfo::OtherInfo & Info)1990b57cec5SDimitry Andric void yaml::MappingTraits<CPUInfo::OtherInfo>::mapping(
2000b57cec5SDimitry Andric     IO &IO, CPUInfo::OtherInfo &Info) {
2010b57cec5SDimitry Andric   FixedSizeHex<sizeof(Info.ProcessorFeatures)> Features(Info.ProcessorFeatures);
2020b57cec5SDimitry Andric   IO.mapRequired("Features", Features);
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric namespace {
2060b57cec5SDimitry Andric /// A type which only accepts strings of a fixed size for yaml conversion.
2070b57cec5SDimitry Andric template <std::size_t N> struct FixedSizeString {
FixedSizeString__anon2018ce470311::FixedSizeString2080b57cec5SDimitry Andric   FixedSizeString(char (&Storage)[N]) : Storage(Storage) {}
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   char (&Storage)[N];
2110b57cec5SDimitry Andric };
2120b57cec5SDimitry Andric } // namespace
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric namespace llvm {
2150b57cec5SDimitry Andric namespace yaml {
2160b57cec5SDimitry Andric template <std::size_t N> struct ScalarTraits<FixedSizeString<N>> {
outputllvm::yaml::ScalarTraits2170b57cec5SDimitry Andric   static void output(const FixedSizeString<N> &Fixed, void *, raw_ostream &OS) {
2180b57cec5SDimitry Andric     OS << StringRef(Fixed.Storage, N);
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric 
inputllvm::yaml::ScalarTraits2210b57cec5SDimitry Andric   static StringRef input(StringRef Scalar, void *, FixedSizeString<N> &Fixed) {
2220b57cec5SDimitry Andric     if (Scalar.size() < N)
2230b57cec5SDimitry Andric       return "String too short";
2240b57cec5SDimitry Andric     if (Scalar.size() > N)
2250b57cec5SDimitry Andric       return "String too long";
2260b57cec5SDimitry Andric     copy(Scalar, Fixed.Storage);
2270b57cec5SDimitry Andric     return "";
2280b57cec5SDimitry Andric   }
2290b57cec5SDimitry Andric 
mustQuotellvm::yaml::ScalarTraits2300b57cec5SDimitry Andric   static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
2310b57cec5SDimitry Andric };
2320b57cec5SDimitry Andric } // namespace yaml
2330b57cec5SDimitry Andric } // namespace llvm
2340b57cec5SDimitry Andric 
mapping(IO & IO,CPUInfo::X86Info & Info)2350b57cec5SDimitry Andric void yaml::MappingTraits<CPUInfo::X86Info>::mapping(IO &IO,
2360b57cec5SDimitry Andric                                                     CPUInfo::X86Info &Info) {
2370b57cec5SDimitry Andric   FixedSizeString<sizeof(Info.VendorID)> VendorID(Info.VendorID);
2380b57cec5SDimitry Andric   IO.mapRequired("Vendor ID", VendorID);
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   mapRequiredHex(IO, "Version Info", Info.VersionInfo);
2410b57cec5SDimitry Andric   mapRequiredHex(IO, "Feature Info", Info.FeatureInfo);
2420b57cec5SDimitry Andric   mapOptionalHex(IO, "AMD Extended Features", Info.AMDExtendedFeatures, 0);
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric 
mapping(IO & IO,MemoryInfo & Info)2458bcb0991SDimitry Andric void yaml::MappingTraits<MemoryInfo>::mapping(IO &IO, MemoryInfo &Info) {
2468bcb0991SDimitry Andric   mapRequiredHex(IO, "Base Address", Info.BaseAddress);
2478bcb0991SDimitry Andric   mapOptionalHex(IO, "Allocation Base", Info.AllocationBase, Info.BaseAddress);
2488bcb0991SDimitry Andric   mapRequiredAs<MemoryProtection>(IO, "Allocation Protect",
2498bcb0991SDimitry Andric                                   Info.AllocationProtect);
2508bcb0991SDimitry Andric   mapOptionalHex(IO, "Reserved0", Info.Reserved0, 0);
2518bcb0991SDimitry Andric   mapRequiredHex(IO, "Region Size", Info.RegionSize);
2528bcb0991SDimitry Andric   mapRequiredAs<MemoryState>(IO, "State", Info.State);
2538bcb0991SDimitry Andric   mapOptionalAs<MemoryProtection>(IO, "Protect", Info.Protect,
2548bcb0991SDimitry Andric                                   Info.AllocationProtect);
2558bcb0991SDimitry Andric   mapRequiredAs<MemoryType>(IO, "Type", Info.Type);
2568bcb0991SDimitry Andric   mapOptionalHex(IO, "Reserved1", Info.Reserved1, 0);
2578bcb0991SDimitry Andric }
2588bcb0991SDimitry Andric 
mapping(IO & IO,VSFixedFileInfo & Info)2590b57cec5SDimitry Andric void yaml::MappingTraits<VSFixedFileInfo>::mapping(IO &IO,
2600b57cec5SDimitry Andric                                                    VSFixedFileInfo &Info) {
2610b57cec5SDimitry Andric   mapOptionalHex(IO, "Signature", Info.Signature, 0);
2620b57cec5SDimitry Andric   mapOptionalHex(IO, "Struct Version", Info.StructVersion, 0);
2630b57cec5SDimitry Andric   mapOptionalHex(IO, "File Version High", Info.FileVersionHigh, 0);
2640b57cec5SDimitry Andric   mapOptionalHex(IO, "File Version Low", Info.FileVersionLow, 0);
2650b57cec5SDimitry Andric   mapOptionalHex(IO, "Product Version High", Info.ProductVersionHigh, 0);
2660b57cec5SDimitry Andric   mapOptionalHex(IO, "Product Version Low", Info.ProductVersionLow, 0);
2670b57cec5SDimitry Andric   mapOptionalHex(IO, "File Flags Mask", Info.FileFlagsMask, 0);
2680b57cec5SDimitry Andric   mapOptionalHex(IO, "File Flags", Info.FileFlags, 0);
2690b57cec5SDimitry Andric   mapOptionalHex(IO, "File OS", Info.FileOS, 0);
2700b57cec5SDimitry Andric   mapOptionalHex(IO, "File Type", Info.FileType, 0);
2710b57cec5SDimitry Andric   mapOptionalHex(IO, "File Subtype", Info.FileSubtype, 0);
2720b57cec5SDimitry Andric   mapOptionalHex(IO, "File Date High", Info.FileDateHigh, 0);
2730b57cec5SDimitry Andric   mapOptionalHex(IO, "File Date Low", Info.FileDateLow, 0);
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric 
mapping(IO & IO,ModuleListStream::entry_type & M)2760b57cec5SDimitry Andric void yaml::MappingTraits<ModuleListStream::entry_type>::mapping(
2770b57cec5SDimitry Andric     IO &IO, ModuleListStream::entry_type &M) {
2780b57cec5SDimitry Andric   mapRequiredHex(IO, "Base of Image", M.Entry.BaseOfImage);
2790b57cec5SDimitry Andric   mapRequiredHex(IO, "Size of Image", M.Entry.SizeOfImage);
2800b57cec5SDimitry Andric   mapOptionalHex(IO, "Checksum", M.Entry.Checksum, 0);
2818bcb0991SDimitry Andric   mapOptional(IO, "Time Date Stamp", M.Entry.TimeDateStamp, 0);
2820b57cec5SDimitry Andric   IO.mapRequired("Module Name", M.Name);
2830b57cec5SDimitry Andric   IO.mapOptional("Version Info", M.Entry.VersionInfo, VSFixedFileInfo());
2840b57cec5SDimitry Andric   IO.mapRequired("CodeView Record", M.CvRecord);
2850b57cec5SDimitry Andric   IO.mapOptional("Misc Record", M.MiscRecord, yaml::BinaryRef());
2860b57cec5SDimitry Andric   mapOptionalHex(IO, "Reserved0", M.Entry.Reserved0, 0);
2870b57cec5SDimitry Andric   mapOptionalHex(IO, "Reserved1", M.Entry.Reserved1, 0);
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric 
streamMapping(yaml::IO & IO,RawContentStream & Stream)2900b57cec5SDimitry Andric static void streamMapping(yaml::IO &IO, RawContentStream &Stream) {
2910b57cec5SDimitry Andric   IO.mapOptional("Content", Stream.Content);
2920b57cec5SDimitry Andric   IO.mapOptional("Size", Stream.Size, Stream.Content.binary_size());
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric 
streamValidate(RawContentStream & Stream)295e8d8bef9SDimitry Andric static std::string streamValidate(RawContentStream &Stream) {
2960b57cec5SDimitry Andric   if (Stream.Size.value < Stream.Content.binary_size())
2970b57cec5SDimitry Andric     return "Stream size must be greater or equal to the content size";
2980b57cec5SDimitry Andric   return "";
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric 
mapping(IO & IO,MemoryListStream::entry_type & Range)3010b57cec5SDimitry Andric void yaml::MappingTraits<MemoryListStream::entry_type>::mapping(
3020b57cec5SDimitry Andric     IO &IO, MemoryListStream::entry_type &Range) {
3030b57cec5SDimitry Andric   MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
3040b57cec5SDimitry Andric       IO, Range.Entry, Range.Content);
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric 
streamMapping(yaml::IO & IO,MemoryInfoListStream & Stream)3078bcb0991SDimitry Andric static void streamMapping(yaml::IO &IO, MemoryInfoListStream &Stream) {
3088bcb0991SDimitry Andric   IO.mapRequired("Memory Ranges", Stream.Infos);
3098bcb0991SDimitry Andric }
3108bcb0991SDimitry Andric 
streamMapping(yaml::IO & IO,MemoryListStream & Stream)3110b57cec5SDimitry Andric static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) {
3120b57cec5SDimitry Andric   IO.mapRequired("Memory Ranges", Stream.Entries);
3130b57cec5SDimitry Andric }
3140b57cec5SDimitry Andric 
streamMapping(yaml::IO & IO,ModuleListStream & Stream)3150b57cec5SDimitry Andric static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) {
3160b57cec5SDimitry Andric   IO.mapRequired("Modules", Stream.Entries);
3170b57cec5SDimitry Andric }
3180b57cec5SDimitry Andric 
streamMapping(yaml::IO & IO,SystemInfoStream & Stream)3190b57cec5SDimitry Andric static void streamMapping(yaml::IO &IO, SystemInfoStream &Stream) {
3200b57cec5SDimitry Andric   SystemInfo &Info = Stream.Info;
3210b57cec5SDimitry Andric   IO.mapRequired("Processor Arch", Info.ProcessorArch);
3220b57cec5SDimitry Andric   mapOptional(IO, "Processor Level", Info.ProcessorLevel, 0);
3230b57cec5SDimitry Andric   mapOptional(IO, "Processor Revision", Info.ProcessorRevision, 0);
3240b57cec5SDimitry Andric   IO.mapOptional("Number of Processors", Info.NumberOfProcessors, 0);
3250b57cec5SDimitry Andric   IO.mapOptional("Product type", Info.ProductType, 0);
3260b57cec5SDimitry Andric   mapOptional(IO, "Major Version", Info.MajorVersion, 0);
3270b57cec5SDimitry Andric   mapOptional(IO, "Minor Version", Info.MinorVersion, 0);
3280b57cec5SDimitry Andric   mapOptional(IO, "Build Number", Info.BuildNumber, 0);
3290b57cec5SDimitry Andric   IO.mapRequired("Platform ID", Info.PlatformId);
3300b57cec5SDimitry Andric   IO.mapOptional("CSD Version", Stream.CSDVersion, "");
3310b57cec5SDimitry Andric   mapOptionalHex(IO, "Suite Mask", Info.SuiteMask, 0);
3320b57cec5SDimitry Andric   mapOptionalHex(IO, "Reserved", Info.Reserved, 0);
3330b57cec5SDimitry Andric   switch (static_cast<ProcessorArchitecture>(Info.ProcessorArch)) {
3340b57cec5SDimitry Andric   case ProcessorArchitecture::X86:
3350b57cec5SDimitry Andric   case ProcessorArchitecture::AMD64:
3360b57cec5SDimitry Andric     IO.mapOptional("CPU", Info.CPU.X86);
3370b57cec5SDimitry Andric     break;
3380b57cec5SDimitry Andric   case ProcessorArchitecture::ARM:
3390b57cec5SDimitry Andric   case ProcessorArchitecture::ARM64:
340480093f4SDimitry Andric   case ProcessorArchitecture::BP_ARM64:
3410b57cec5SDimitry Andric     IO.mapOptional("CPU", Info.CPU.Arm);
3420b57cec5SDimitry Andric     break;
3430b57cec5SDimitry Andric   default:
3440b57cec5SDimitry Andric     IO.mapOptional("CPU", Info.CPU.Other);
3450b57cec5SDimitry Andric     break;
3460b57cec5SDimitry Andric   }
3470b57cec5SDimitry Andric }
3480b57cec5SDimitry Andric 
streamMapping(yaml::IO & IO,TextContentStream & Stream)3490b57cec5SDimitry Andric static void streamMapping(yaml::IO &IO, TextContentStream &Stream) {
3500b57cec5SDimitry Andric   IO.mapOptional("Text", Stream.Text);
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric 
mapping(IO & IO,MemoryDescriptor & Memory,BinaryRef & Content)3530b57cec5SDimitry Andric void yaml::MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
3540b57cec5SDimitry Andric     IO &IO, MemoryDescriptor &Memory, BinaryRef &Content) {
3550b57cec5SDimitry Andric   mapRequiredHex(IO, "Start of Memory Range", Memory.StartOfMemoryRange);
3560b57cec5SDimitry Andric   IO.mapRequired("Content", Content);
3570b57cec5SDimitry Andric }
3580b57cec5SDimitry Andric 
mapping(IO & IO,ThreadListStream::entry_type & T)3590b57cec5SDimitry Andric void yaml::MappingTraits<ThreadListStream::entry_type>::mapping(
3600b57cec5SDimitry Andric     IO &IO, ThreadListStream::entry_type &T) {
3610b57cec5SDimitry Andric   mapRequiredHex(IO, "Thread Id", T.Entry.ThreadId);
3620b57cec5SDimitry Andric   mapOptionalHex(IO, "Suspend Count", T.Entry.SuspendCount, 0);
3630b57cec5SDimitry Andric   mapOptionalHex(IO, "Priority Class", T.Entry.PriorityClass, 0);
3640b57cec5SDimitry Andric   mapOptionalHex(IO, "Priority", T.Entry.Priority, 0);
3650b57cec5SDimitry Andric   mapOptionalHex(IO, "Environment Block", T.Entry.EnvironmentBlock, 0);
3660b57cec5SDimitry Andric   IO.mapRequired("Context", T.Context);
3670b57cec5SDimitry Andric   IO.mapRequired("Stack", T.Entry.Stack, T.Stack);
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric 
streamMapping(yaml::IO & IO,ThreadListStream & Stream)3700b57cec5SDimitry Andric static void streamMapping(yaml::IO &IO, ThreadListStream &Stream) {
3710b57cec5SDimitry Andric   IO.mapRequired("Threads", Stream.Entries);
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric 
streamMapping(yaml::IO & IO,MinidumpYAML::ExceptionStream & Stream)3748bcb0991SDimitry Andric static void streamMapping(yaml::IO &IO, MinidumpYAML::ExceptionStream &Stream) {
3758bcb0991SDimitry Andric   mapRequiredHex(IO, "Thread ID", Stream.MDExceptionStream.ThreadId);
3768bcb0991SDimitry Andric   IO.mapRequired("Exception Record", Stream.MDExceptionStream.ExceptionRecord);
3778bcb0991SDimitry Andric   IO.mapRequired("Thread Context", Stream.ThreadContext);
3788bcb0991SDimitry Andric }
3798bcb0991SDimitry Andric 
mapping(yaml::IO & IO,minidump::Exception & Exception)3808bcb0991SDimitry Andric void yaml::MappingTraits<minidump::Exception>::mapping(
3818bcb0991SDimitry Andric     yaml::IO &IO, minidump::Exception &Exception) {
3828bcb0991SDimitry Andric   mapRequiredHex(IO, "Exception Code", Exception.ExceptionCode);
3838bcb0991SDimitry Andric   mapOptionalHex(IO, "Exception Flags", Exception.ExceptionFlags, 0);
3848bcb0991SDimitry Andric   mapOptionalHex(IO, "Exception Record", Exception.ExceptionRecord, 0);
3858bcb0991SDimitry Andric   mapOptionalHex(IO, "Exception Address", Exception.ExceptionAddress, 0);
3868bcb0991SDimitry Andric   mapOptional(IO, "Number of Parameters", Exception.NumberParameters, 0);
3878bcb0991SDimitry Andric 
3888bcb0991SDimitry Andric   for (size_t Index = 0; Index < Exception.MaxParameters; ++Index) {
3898bcb0991SDimitry Andric     SmallString<16> Name("Parameter ");
3908bcb0991SDimitry Andric     Twine(Index).toVector(Name);
3918bcb0991SDimitry Andric     support::ulittle64_t &Field = Exception.ExceptionInformation[Index];
3928bcb0991SDimitry Andric 
3938bcb0991SDimitry Andric     if (Index < Exception.NumberParameters)
3948bcb0991SDimitry Andric       mapRequiredHex(IO, Name.c_str(), Field);
3958bcb0991SDimitry Andric     else
3968bcb0991SDimitry Andric       mapOptionalHex(IO, Name.c_str(), Field, 0);
3978bcb0991SDimitry Andric   }
3988bcb0991SDimitry Andric }
3998bcb0991SDimitry Andric 
mapping(yaml::IO & IO,std::unique_ptr<MinidumpYAML::Stream> & S)4000b57cec5SDimitry Andric void yaml::MappingTraits<std::unique_ptr<Stream>>::mapping(
4010b57cec5SDimitry Andric     yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) {
4020b57cec5SDimitry Andric   StreamType Type;
4030b57cec5SDimitry Andric   if (IO.outputting())
4040b57cec5SDimitry Andric     Type = S->Type;
4050b57cec5SDimitry Andric   IO.mapRequired("Type", Type);
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric   if (!IO.outputting())
4080b57cec5SDimitry Andric     S = MinidumpYAML::Stream::create(Type);
4090b57cec5SDimitry Andric   switch (S->Kind) {
4108bcb0991SDimitry Andric   case MinidumpYAML::Stream::StreamKind::Exception:
4118bcb0991SDimitry Andric     streamMapping(IO, llvm::cast<MinidumpYAML::ExceptionStream>(*S));
4128bcb0991SDimitry Andric     break;
4138bcb0991SDimitry Andric   case MinidumpYAML::Stream::StreamKind::MemoryInfoList:
4148bcb0991SDimitry Andric     streamMapping(IO, llvm::cast<MemoryInfoListStream>(*S));
4158bcb0991SDimitry Andric     break;
4160b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::MemoryList:
4170b57cec5SDimitry Andric     streamMapping(IO, llvm::cast<MemoryListStream>(*S));
4180b57cec5SDimitry Andric     break;
4190b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::ModuleList:
4200b57cec5SDimitry Andric     streamMapping(IO, llvm::cast<ModuleListStream>(*S));
4210b57cec5SDimitry Andric     break;
4220b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::RawContent:
4230b57cec5SDimitry Andric     streamMapping(IO, llvm::cast<RawContentStream>(*S));
4240b57cec5SDimitry Andric     break;
4250b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::SystemInfo:
4260b57cec5SDimitry Andric     streamMapping(IO, llvm::cast<SystemInfoStream>(*S));
4270b57cec5SDimitry Andric     break;
4280b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::TextContent:
4290b57cec5SDimitry Andric     streamMapping(IO, llvm::cast<TextContentStream>(*S));
4300b57cec5SDimitry Andric     break;
4310b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::ThreadList:
4320b57cec5SDimitry Andric     streamMapping(IO, llvm::cast<ThreadListStream>(*S));
4330b57cec5SDimitry Andric     break;
4340b57cec5SDimitry Andric   }
4350b57cec5SDimitry Andric }
4360b57cec5SDimitry Andric 
validate(yaml::IO & IO,std::unique_ptr<MinidumpYAML::Stream> & S)437e8d8bef9SDimitry Andric std::string yaml::MappingTraits<std::unique_ptr<Stream>>::validate(
4380b57cec5SDimitry Andric     yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) {
4390b57cec5SDimitry Andric   switch (S->Kind) {
4400b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::RawContent:
4410b57cec5SDimitry Andric     return streamValidate(cast<RawContentStream>(*S));
4428bcb0991SDimitry Andric   case MinidumpYAML::Stream::StreamKind::Exception:
4438bcb0991SDimitry Andric   case MinidumpYAML::Stream::StreamKind::MemoryInfoList:
4440b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::MemoryList:
4450b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::ModuleList:
4460b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::SystemInfo:
4470b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::TextContent:
4480b57cec5SDimitry Andric   case MinidumpYAML::Stream::StreamKind::ThreadList:
4490b57cec5SDimitry Andric     return "";
4500b57cec5SDimitry Andric   }
4510b57cec5SDimitry Andric   llvm_unreachable("Fully covered switch above!");
4520b57cec5SDimitry Andric }
4530b57cec5SDimitry Andric 
mapping(IO & IO,Object & O)4540b57cec5SDimitry Andric void yaml::MappingTraits<Object>::mapping(IO &IO, Object &O) {
4550b57cec5SDimitry Andric   IO.mapTag("!minidump", true);
4560b57cec5SDimitry Andric   mapOptionalHex(IO, "Signature", O.Header.Signature, Header::MagicSignature);
4570b57cec5SDimitry Andric   mapOptionalHex(IO, "Version", O.Header.Version, Header::MagicVersion);
4580b57cec5SDimitry Andric   mapOptionalHex(IO, "Flags", O.Header.Flags, 0);
4590b57cec5SDimitry Andric   IO.mapRequired("Streams", O.Streams);
4600b57cec5SDimitry Andric }
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric Expected<std::unique_ptr<Stream>>
create(const Directory & StreamDesc,const object::MinidumpFile & File)4630b57cec5SDimitry Andric Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
4640b57cec5SDimitry Andric   StreamKind Kind = getKind(StreamDesc.Type);
4650b57cec5SDimitry Andric   switch (Kind) {
4668bcb0991SDimitry Andric   case StreamKind::Exception: {
4678bcb0991SDimitry Andric     Expected<const minidump::ExceptionStream &> ExpectedExceptionStream =
4688bcb0991SDimitry Andric         File.getExceptionStream();
4698bcb0991SDimitry Andric     if (!ExpectedExceptionStream)
4708bcb0991SDimitry Andric       return ExpectedExceptionStream.takeError();
4718bcb0991SDimitry Andric     Expected<ArrayRef<uint8_t>> ExpectedThreadContext =
4728bcb0991SDimitry Andric         File.getRawData(ExpectedExceptionStream->ThreadContext);
4738bcb0991SDimitry Andric     if (!ExpectedThreadContext)
4748bcb0991SDimitry Andric       return ExpectedThreadContext.takeError();
4758bcb0991SDimitry Andric     return std::make_unique<ExceptionStream>(*ExpectedExceptionStream,
4768bcb0991SDimitry Andric                                              *ExpectedThreadContext);
4778bcb0991SDimitry Andric   }
4788bcb0991SDimitry Andric   case StreamKind::MemoryInfoList: {
4798bcb0991SDimitry Andric     if (auto ExpectedList = File.getMemoryInfoList())
4808bcb0991SDimitry Andric       return std::make_unique<MemoryInfoListStream>(*ExpectedList);
4818bcb0991SDimitry Andric     else
4828bcb0991SDimitry Andric       return ExpectedList.takeError();
4838bcb0991SDimitry Andric   }
4840b57cec5SDimitry Andric   case StreamKind::MemoryList: {
4850b57cec5SDimitry Andric     auto ExpectedList = File.getMemoryList();
4860b57cec5SDimitry Andric     if (!ExpectedList)
4870b57cec5SDimitry Andric       return ExpectedList.takeError();
4880b57cec5SDimitry Andric     std::vector<MemoryListStream::entry_type> Ranges;
4890b57cec5SDimitry Andric     for (const MemoryDescriptor &MD : *ExpectedList) {
4900b57cec5SDimitry Andric       auto ExpectedContent = File.getRawData(MD.Memory);
4910b57cec5SDimitry Andric       if (!ExpectedContent)
4920b57cec5SDimitry Andric         return ExpectedContent.takeError();
4930b57cec5SDimitry Andric       Ranges.push_back({MD, *ExpectedContent});
4940b57cec5SDimitry Andric     }
4958bcb0991SDimitry Andric     return std::make_unique<MemoryListStream>(std::move(Ranges));
4960b57cec5SDimitry Andric   }
4970b57cec5SDimitry Andric   case StreamKind::ModuleList: {
4980b57cec5SDimitry Andric     auto ExpectedList = File.getModuleList();
4990b57cec5SDimitry Andric     if (!ExpectedList)
5000b57cec5SDimitry Andric       return ExpectedList.takeError();
5010b57cec5SDimitry Andric     std::vector<ModuleListStream::entry_type> Modules;
5020b57cec5SDimitry Andric     for (const Module &M : *ExpectedList) {
5030b57cec5SDimitry Andric       auto ExpectedName = File.getString(M.ModuleNameRVA);
5040b57cec5SDimitry Andric       if (!ExpectedName)
5050b57cec5SDimitry Andric         return ExpectedName.takeError();
5060b57cec5SDimitry Andric       auto ExpectedCv = File.getRawData(M.CvRecord);
5070b57cec5SDimitry Andric       if (!ExpectedCv)
5080b57cec5SDimitry Andric         return ExpectedCv.takeError();
5090b57cec5SDimitry Andric       auto ExpectedMisc = File.getRawData(M.MiscRecord);
5100b57cec5SDimitry Andric       if (!ExpectedMisc)
5110b57cec5SDimitry Andric         return ExpectedMisc.takeError();
5120b57cec5SDimitry Andric       Modules.push_back(
5130b57cec5SDimitry Andric           {M, std::move(*ExpectedName), *ExpectedCv, *ExpectedMisc});
5140b57cec5SDimitry Andric     }
5158bcb0991SDimitry Andric     return std::make_unique<ModuleListStream>(std::move(Modules));
5160b57cec5SDimitry Andric   }
5170b57cec5SDimitry Andric   case StreamKind::RawContent:
5188bcb0991SDimitry Andric     return std::make_unique<RawContentStream>(StreamDesc.Type,
5190b57cec5SDimitry Andric                                                File.getRawStream(StreamDesc));
5200b57cec5SDimitry Andric   case StreamKind::SystemInfo: {
5210b57cec5SDimitry Andric     auto ExpectedInfo = File.getSystemInfo();
5220b57cec5SDimitry Andric     if (!ExpectedInfo)
5230b57cec5SDimitry Andric       return ExpectedInfo.takeError();
5240b57cec5SDimitry Andric     auto ExpectedCSDVersion = File.getString(ExpectedInfo->CSDVersionRVA);
5250b57cec5SDimitry Andric     if (!ExpectedCSDVersion)
5260b57cec5SDimitry Andric       return ExpectedInfo.takeError();
5278bcb0991SDimitry Andric     return std::make_unique<SystemInfoStream>(*ExpectedInfo,
5280b57cec5SDimitry Andric                                                std::move(*ExpectedCSDVersion));
5290b57cec5SDimitry Andric   }
5300b57cec5SDimitry Andric   case StreamKind::TextContent:
5318bcb0991SDimitry Andric     return std::make_unique<TextContentStream>(
5320b57cec5SDimitry Andric         StreamDesc.Type, toStringRef(File.getRawStream(StreamDesc)));
5330b57cec5SDimitry Andric   case StreamKind::ThreadList: {
5340b57cec5SDimitry Andric     auto ExpectedList = File.getThreadList();
5350b57cec5SDimitry Andric     if (!ExpectedList)
5360b57cec5SDimitry Andric       return ExpectedList.takeError();
5370b57cec5SDimitry Andric     std::vector<ThreadListStream::entry_type> Threads;
5380b57cec5SDimitry Andric     for (const Thread &T : *ExpectedList) {
5390b57cec5SDimitry Andric       auto ExpectedStack = File.getRawData(T.Stack.Memory);
5400b57cec5SDimitry Andric       if (!ExpectedStack)
5410b57cec5SDimitry Andric         return ExpectedStack.takeError();
5420b57cec5SDimitry Andric       auto ExpectedContext = File.getRawData(T.Context);
5430b57cec5SDimitry Andric       if (!ExpectedContext)
5440b57cec5SDimitry Andric         return ExpectedContext.takeError();
5450b57cec5SDimitry Andric       Threads.push_back({T, *ExpectedStack, *ExpectedContext});
5460b57cec5SDimitry Andric     }
5478bcb0991SDimitry Andric     return std::make_unique<ThreadListStream>(std::move(Threads));
5480b57cec5SDimitry Andric   }
5490b57cec5SDimitry Andric   }
5500b57cec5SDimitry Andric   llvm_unreachable("Unhandled stream kind!");
5510b57cec5SDimitry Andric }
5520b57cec5SDimitry Andric 
create(const object::MinidumpFile & File)5530b57cec5SDimitry Andric Expected<Object> Object::create(const object::MinidumpFile &File) {
5540b57cec5SDimitry Andric   std::vector<std::unique_ptr<Stream>> Streams;
5550b57cec5SDimitry Andric   Streams.reserve(File.streams().size());
5560b57cec5SDimitry Andric   for (const Directory &StreamDesc : File.streams()) {
5570b57cec5SDimitry Andric     auto ExpectedStream = Stream::create(StreamDesc, File);
5580b57cec5SDimitry Andric     if (!ExpectedStream)
5590b57cec5SDimitry Andric       return ExpectedStream.takeError();
5600b57cec5SDimitry Andric     Streams.push_back(std::move(*ExpectedStream));
5610b57cec5SDimitry Andric   }
5620b57cec5SDimitry Andric   return Object(File.header(), std::move(Streams));
5630b57cec5SDimitry Andric }
564