xref: /llvm-project/llvm/lib/ObjectYAML/MinidumpYAML.cpp (revision 5b7102d1f37eab7a8f17b7bf4124ca76fbdbd66d)
169de7a95SPavel Labath //===- MinidumpYAML.cpp - Minidump YAMLIO implementation ------------------===//
269de7a95SPavel Labath //
369de7a95SPavel Labath // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
469de7a95SPavel Labath // See https://llvm.org/LICENSE.txt for license information.
569de7a95SPavel Labath // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
669de7a95SPavel Labath //
769de7a95SPavel Labath //===----------------------------------------------------------------------===//
869de7a95SPavel Labath 
969de7a95SPavel Labath #include "llvm/ObjectYAML/MinidumpYAML.h"
1069de7a95SPavel Labath 
1169de7a95SPavel Labath using namespace llvm;
1269de7a95SPavel Labath using namespace llvm::MinidumpYAML;
1369de7a95SPavel Labath using namespace llvm::minidump;
1469de7a95SPavel Labath 
1569de7a95SPavel Labath /// Perform an optional yaml-mapping of an endian-aware type EndianType. The
1669de7a95SPavel Labath /// only purpose of this function is to avoid casting the Default value to the
1769de7a95SPavel Labath /// endian type;
1869de7a95SPavel Labath template <typename EndianType>
1969de7a95SPavel Labath static inline void mapOptional(yaml::IO &IO, const char *Key, EndianType &Val,
2069de7a95SPavel Labath                                typename EndianType::value_type Default) {
2169de7a95SPavel Labath   IO.mapOptional(Key, Val, EndianType(Default));
2269de7a95SPavel Labath }
2369de7a95SPavel Labath 
2469de7a95SPavel Labath /// Yaml-map an endian-aware type EndianType as some other type MapType.
2569de7a95SPavel Labath template <typename MapType, typename EndianType>
2669de7a95SPavel Labath static inline void mapRequiredAs(yaml::IO &IO, const char *Key,
2769de7a95SPavel Labath                                  EndianType &Val) {
2869de7a95SPavel Labath   MapType Mapped = static_cast<typename EndianType::value_type>(Val);
2969de7a95SPavel Labath   IO.mapRequired(Key, Mapped);
3069de7a95SPavel Labath   Val = static_cast<typename EndianType::value_type>(Mapped);
3169de7a95SPavel Labath }
3269de7a95SPavel Labath 
3369de7a95SPavel Labath /// Perform an optional yaml-mapping of an endian-aware type EndianType as some
3469de7a95SPavel Labath /// other type MapType.
3569de7a95SPavel Labath template <typename MapType, typename EndianType>
3669de7a95SPavel Labath static inline void mapOptionalAs(yaml::IO &IO, const char *Key, EndianType &Val,
3769de7a95SPavel Labath                                  MapType Default) {
3869de7a95SPavel Labath   MapType Mapped = static_cast<typename EndianType::value_type>(Val);
3969de7a95SPavel Labath   IO.mapOptional(Key, Mapped, Default);
4069de7a95SPavel Labath   Val = static_cast<typename EndianType::value_type>(Mapped);
4169de7a95SPavel Labath }
4269de7a95SPavel Labath 
4369de7a95SPavel Labath namespace {
4469de7a95SPavel Labath /// Return the appropriate yaml Hex type for a given endian-aware type.
4569de7a95SPavel Labath template <typename EndianType> struct HexType;
4669de7a95SPavel Labath template <> struct HexType<support::ulittle16_t> { using type = yaml::Hex16; };
4769de7a95SPavel Labath template <> struct HexType<support::ulittle32_t> { using type = yaml::Hex32; };
4869de7a95SPavel Labath template <> struct HexType<support::ulittle64_t> { using type = yaml::Hex64; };
4969de7a95SPavel Labath } // namespace
5069de7a95SPavel Labath 
5169de7a95SPavel Labath /// Yaml-map an endian-aware type as an appropriately-sized hex value.
5269de7a95SPavel Labath template <typename EndianType>
5369de7a95SPavel Labath static inline void mapRequiredHex(yaml::IO &IO, const char *Key,
5469de7a95SPavel Labath                                   EndianType &Val) {
5569de7a95SPavel Labath   mapRequiredAs<typename HexType<EndianType>::type>(IO, Key, Val);
5669de7a95SPavel Labath }
5769de7a95SPavel Labath 
5869de7a95SPavel Labath /// Perform an optional yaml-mapping of an endian-aware type as an
5969de7a95SPavel Labath /// appropriately-sized hex value.
6069de7a95SPavel Labath template <typename EndianType>
6169de7a95SPavel Labath static inline void mapOptionalHex(yaml::IO &IO, const char *Key,
6269de7a95SPavel Labath                                   EndianType &Val,
6369de7a95SPavel Labath                                   typename EndianType::value_type Default) {
6469de7a95SPavel Labath   mapOptionalAs<typename HexType<EndianType>::type>(IO, Key, Val, Default);
6569de7a95SPavel Labath }
6669de7a95SPavel Labath 
6769de7a95SPavel Labath Stream::~Stream() = default;
6869de7a95SPavel Labath 
6969de7a95SPavel Labath Stream::StreamKind Stream::getKind(StreamType Type) {
7069de7a95SPavel Labath   switch (Type) {
71a50272f8SJoseph Tremoulet   case StreamType::Exception:
72a50272f8SJoseph Tremoulet     return StreamKind::Exception;
733aa7e766SPavel Labath   case StreamType::MemoryInfoList:
743aa7e766SPavel Labath     return StreamKind::MemoryInfoList;
752d29e16cSPavel Labath   case StreamType::MemoryList:
762d29e16cSPavel Labath     return StreamKind::MemoryList;
77b1edac04SJacob Lalonde   case StreamType::Memory64List:
78b1edac04SJacob Lalonde     return StreamKind::Memory64List;
797429d86fSPavel Labath   case StreamType::ModuleList:
807429d86fSPavel Labath     return StreamKind::ModuleList;
8169de7a95SPavel Labath   case StreamType::SystemInfo:
8269de7a95SPavel Labath     return StreamKind::SystemInfo;
8369de7a95SPavel Labath   case StreamType::LinuxCPUInfo:
8469de7a95SPavel Labath   case StreamType::LinuxProcStatus:
8569de7a95SPavel Labath   case StreamType::LinuxLSBRelease:
8669de7a95SPavel Labath   case StreamType::LinuxCMDLine:
8769de7a95SPavel Labath   case StreamType::LinuxMaps:
8869de7a95SPavel Labath   case StreamType::LinuxProcStat:
8969de7a95SPavel Labath   case StreamType::LinuxProcUptime:
9069de7a95SPavel Labath     return StreamKind::TextContent;
91dcdb3c66SPavel Labath   case StreamType::ThreadList:
92dcdb3c66SPavel Labath     return StreamKind::ThreadList;
9369de7a95SPavel Labath   default:
9469de7a95SPavel Labath     return StreamKind::RawContent;
9569de7a95SPavel Labath   }
9669de7a95SPavel Labath }
9769de7a95SPavel Labath 
9869de7a95SPavel Labath std::unique_ptr<Stream> Stream::create(StreamType Type) {
9969de7a95SPavel Labath   StreamKind Kind = getKind(Type);
10069de7a95SPavel Labath   switch (Kind) {
101a50272f8SJoseph Tremoulet   case StreamKind::Exception:
102a50272f8SJoseph Tremoulet     return std::make_unique<ExceptionStream>();
1033aa7e766SPavel Labath   case StreamKind::MemoryInfoList:
1043aa7e766SPavel Labath     return std::make_unique<MemoryInfoListStream>();
1052d29e16cSPavel Labath   case StreamKind::MemoryList:
1060eaee545SJonas Devlieghere     return std::make_unique<MemoryListStream>();
107b1edac04SJacob Lalonde   case StreamKind::Memory64List:
108b1edac04SJacob Lalonde     return std::make_unique<Memory64ListStream>();
1097429d86fSPavel Labath   case StreamKind::ModuleList:
1100eaee545SJonas Devlieghere     return std::make_unique<ModuleListStream>();
11169de7a95SPavel Labath   case StreamKind::RawContent:
1120eaee545SJonas Devlieghere     return std::make_unique<RawContentStream>(Type);
11369de7a95SPavel Labath   case StreamKind::SystemInfo:
1140eaee545SJonas Devlieghere     return std::make_unique<SystemInfoStream>();
11569de7a95SPavel Labath   case StreamKind::TextContent:
1160eaee545SJonas Devlieghere     return std::make_unique<TextContentStream>(Type);
117dcdb3c66SPavel Labath   case StreamKind::ThreadList:
1180eaee545SJonas Devlieghere     return std::make_unique<ThreadListStream>();
11969de7a95SPavel Labath   }
12069de7a95SPavel Labath   llvm_unreachable("Unhandled stream kind!");
12169de7a95SPavel Labath }
12269de7a95SPavel Labath 
1233aa7e766SPavel Labath void yaml::ScalarBitSetTraits<MemoryProtection>::bitset(
1243aa7e766SPavel Labath     IO &IO, MemoryProtection &Protect) {
1253aa7e766SPavel Labath #define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME)                            \
1263aa7e766SPavel Labath   IO.bitSetCase(Protect, #NATIVENAME, MemoryProtection::NAME);
1273aa7e766SPavel Labath #include "llvm/BinaryFormat/MinidumpConstants.def"
1283aa7e766SPavel Labath }
1293aa7e766SPavel Labath 
1303aa7e766SPavel Labath void yaml::ScalarBitSetTraits<MemoryState>::bitset(IO &IO, MemoryState &State) {
1313aa7e766SPavel Labath #define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME)                           \
1323aa7e766SPavel Labath   IO.bitSetCase(State, #NATIVENAME, MemoryState::NAME);
1333aa7e766SPavel Labath #include "llvm/BinaryFormat/MinidumpConstants.def"
1343aa7e766SPavel Labath }
1353aa7e766SPavel Labath 
1363aa7e766SPavel Labath void yaml::ScalarBitSetTraits<MemoryType>::bitset(IO &IO, MemoryType &Type) {
1373aa7e766SPavel Labath #define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME)                            \
1383aa7e766SPavel Labath   IO.bitSetCase(Type, #NATIVENAME, MemoryType::NAME);
1393aa7e766SPavel Labath #include "llvm/BinaryFormat/MinidumpConstants.def"
1403aa7e766SPavel Labath }
1413aa7e766SPavel Labath 
14269de7a95SPavel Labath void yaml::ScalarEnumerationTraits<ProcessorArchitecture>::enumeration(
14369de7a95SPavel Labath     IO &IO, ProcessorArchitecture &Arch) {
14469de7a95SPavel Labath #define HANDLE_MDMP_ARCH(CODE, NAME)                                           \
14569de7a95SPavel Labath   IO.enumCase(Arch, #NAME, ProcessorArchitecture::NAME);
14669de7a95SPavel Labath #include "llvm/BinaryFormat/MinidumpConstants.def"
14769de7a95SPavel Labath   IO.enumFallback<Hex16>(Arch);
14869de7a95SPavel Labath }
14969de7a95SPavel Labath 
15069de7a95SPavel Labath void yaml::ScalarEnumerationTraits<OSPlatform>::enumeration(IO &IO,
15169de7a95SPavel Labath                                                             OSPlatform &Plat) {
15269de7a95SPavel Labath #define HANDLE_MDMP_PLATFORM(CODE, NAME)                                       \
15369de7a95SPavel Labath   IO.enumCase(Plat, #NAME, OSPlatform::NAME);
15469de7a95SPavel Labath #include "llvm/BinaryFormat/MinidumpConstants.def"
15569de7a95SPavel Labath   IO.enumFallback<Hex32>(Plat);
15669de7a95SPavel Labath }
15769de7a95SPavel Labath 
15869de7a95SPavel Labath void yaml::ScalarEnumerationTraits<StreamType>::enumeration(IO &IO,
15969de7a95SPavel Labath                                                             StreamType &Type) {
16069de7a95SPavel Labath #define HANDLE_MDMP_STREAM_TYPE(CODE, NAME)                                    \
16169de7a95SPavel Labath   IO.enumCase(Type, #NAME, StreamType::NAME);
16269de7a95SPavel Labath #include "llvm/BinaryFormat/MinidumpConstants.def"
16369de7a95SPavel Labath   IO.enumFallback<Hex32>(Type);
16469de7a95SPavel Labath }
16569de7a95SPavel Labath 
16669de7a95SPavel Labath void yaml::MappingTraits<CPUInfo::ArmInfo>::mapping(IO &IO,
16769de7a95SPavel Labath                                                     CPUInfo::ArmInfo &Info) {
16869de7a95SPavel Labath   mapRequiredHex(IO, "CPUID", Info.CPUID);
16969de7a95SPavel Labath   mapOptionalHex(IO, "ELF hwcaps", Info.ElfHWCaps, 0);
17069de7a95SPavel Labath }
17169de7a95SPavel Labath 
17269de7a95SPavel Labath namespace {
17369de7a95SPavel Labath template <std::size_t N> struct FixedSizeHex {
17469de7a95SPavel Labath   FixedSizeHex(uint8_t (&Storage)[N]) : Storage(Storage) {}
17569de7a95SPavel Labath 
17669de7a95SPavel Labath   uint8_t (&Storage)[N];
17769de7a95SPavel Labath };
17869de7a95SPavel Labath } // namespace
17969de7a95SPavel Labath 
18069de7a95SPavel Labath namespace llvm {
18169de7a95SPavel Labath namespace yaml {
18269de7a95SPavel Labath template <std::size_t N> struct ScalarTraits<FixedSizeHex<N>> {
18369de7a95SPavel Labath   static void output(const FixedSizeHex<N> &Fixed, void *, raw_ostream &OS) {
18438818b60Sserge-sans-paille     OS << toHex(ArrayRef(Fixed.Storage));
18569de7a95SPavel Labath   }
18669de7a95SPavel Labath 
18769de7a95SPavel Labath   static StringRef input(StringRef Scalar, void *, FixedSizeHex<N> &Fixed) {
18869de7a95SPavel Labath     if (!all_of(Scalar, isHexDigit))
18969de7a95SPavel Labath       return "Invalid hex digit in input";
19069de7a95SPavel Labath     if (Scalar.size() < 2 * N)
19169de7a95SPavel Labath       return "String too short";
19269de7a95SPavel Labath     if (Scalar.size() > 2 * N)
19369de7a95SPavel Labath       return "String too long";
19469de7a95SPavel Labath     copy(fromHex(Scalar), Fixed.Storage);
19569de7a95SPavel Labath     return "";
19669de7a95SPavel Labath   }
19769de7a95SPavel Labath 
19869de7a95SPavel Labath   static QuotingType mustQuote(StringRef S) { return QuotingType::None; }
19969de7a95SPavel Labath };
20069de7a95SPavel Labath } // namespace yaml
20169de7a95SPavel Labath } // namespace llvm
20269de7a95SPavel Labath void yaml::MappingTraits<CPUInfo::OtherInfo>::mapping(
20369de7a95SPavel Labath     IO &IO, CPUInfo::OtherInfo &Info) {
20469de7a95SPavel Labath   FixedSizeHex<sizeof(Info.ProcessorFeatures)> Features(Info.ProcessorFeatures);
20569de7a95SPavel Labath   IO.mapRequired("Features", Features);
20669de7a95SPavel Labath }
20769de7a95SPavel Labath 
20869de7a95SPavel Labath namespace {
20969de7a95SPavel Labath /// A type which only accepts strings of a fixed size for yaml conversion.
21069de7a95SPavel Labath template <std::size_t N> struct FixedSizeString {
21169de7a95SPavel Labath   FixedSizeString(char (&Storage)[N]) : Storage(Storage) {}
21269de7a95SPavel Labath 
21369de7a95SPavel Labath   char (&Storage)[N];
21469de7a95SPavel Labath };
21569de7a95SPavel Labath } // namespace
21669de7a95SPavel Labath 
21769de7a95SPavel Labath namespace llvm {
21869de7a95SPavel Labath namespace yaml {
21969de7a95SPavel Labath template <std::size_t N> struct ScalarTraits<FixedSizeString<N>> {
22069de7a95SPavel Labath   static void output(const FixedSizeString<N> &Fixed, void *, raw_ostream &OS) {
22169de7a95SPavel Labath     OS << StringRef(Fixed.Storage, N);
22269de7a95SPavel Labath   }
22369de7a95SPavel Labath 
22469de7a95SPavel Labath   static StringRef input(StringRef Scalar, void *, FixedSizeString<N> &Fixed) {
22569de7a95SPavel Labath     if (Scalar.size() < N)
22669de7a95SPavel Labath       return "String too short";
22769de7a95SPavel Labath     if (Scalar.size() > N)
22869de7a95SPavel Labath       return "String too long";
22969de7a95SPavel Labath     copy(Scalar, Fixed.Storage);
23069de7a95SPavel Labath     return "";
23169de7a95SPavel Labath   }
23269de7a95SPavel Labath 
23369de7a95SPavel Labath   static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
23469de7a95SPavel Labath };
23569de7a95SPavel Labath } // namespace yaml
23669de7a95SPavel Labath } // namespace llvm
23769de7a95SPavel Labath 
23869de7a95SPavel Labath void yaml::MappingTraits<CPUInfo::X86Info>::mapping(IO &IO,
23969de7a95SPavel Labath                                                     CPUInfo::X86Info &Info) {
24069de7a95SPavel Labath   FixedSizeString<sizeof(Info.VendorID)> VendorID(Info.VendorID);
24169de7a95SPavel Labath   IO.mapRequired("Vendor ID", VendorID);
24269de7a95SPavel Labath 
24369de7a95SPavel Labath   mapRequiredHex(IO, "Version Info", Info.VersionInfo);
24469de7a95SPavel Labath   mapRequiredHex(IO, "Feature Info", Info.FeatureInfo);
24569de7a95SPavel Labath   mapOptionalHex(IO, "AMD Extended Features", Info.AMDExtendedFeatures, 0);
24669de7a95SPavel Labath }
24769de7a95SPavel Labath 
2483aa7e766SPavel Labath void yaml::MappingTraits<MemoryInfo>::mapping(IO &IO, MemoryInfo &Info) {
2493aa7e766SPavel Labath   mapRequiredHex(IO, "Base Address", Info.BaseAddress);
2503aa7e766SPavel Labath   mapOptionalHex(IO, "Allocation Base", Info.AllocationBase, Info.BaseAddress);
2513aa7e766SPavel Labath   mapRequiredAs<MemoryProtection>(IO, "Allocation Protect",
2523aa7e766SPavel Labath                                   Info.AllocationProtect);
2533aa7e766SPavel Labath   mapOptionalHex(IO, "Reserved0", Info.Reserved0, 0);
2543aa7e766SPavel Labath   mapRequiredHex(IO, "Region Size", Info.RegionSize);
2553aa7e766SPavel Labath   mapRequiredAs<MemoryState>(IO, "State", Info.State);
2563aa7e766SPavel Labath   mapOptionalAs<MemoryProtection>(IO, "Protect", Info.Protect,
2573aa7e766SPavel Labath                                   Info.AllocationProtect);
2583aa7e766SPavel Labath   mapRequiredAs<MemoryType>(IO, "Type", Info.Type);
2593aa7e766SPavel Labath   mapOptionalHex(IO, "Reserved1", Info.Reserved1, 0);
2603aa7e766SPavel Labath }
2613aa7e766SPavel Labath 
262b1edac04SJacob Lalonde void yaml::MappingTraits<Memory64ListStream::entry_type>::mapping(
263b1edac04SJacob Lalonde     IO &IO, Memory64ListStream::entry_type &Mem) {
264b1edac04SJacob Lalonde   MappingContextTraits<MemoryDescriptor_64, yaml::BinaryRef>::mapping(
265b1edac04SJacob Lalonde       IO, Mem.Entry, Mem.Content);
266b1edac04SJacob Lalonde }
267b1edac04SJacob Lalonde 
2687429d86fSPavel Labath void yaml::MappingTraits<VSFixedFileInfo>::mapping(IO &IO,
2697429d86fSPavel Labath                                                    VSFixedFileInfo &Info) {
2707429d86fSPavel Labath   mapOptionalHex(IO, "Signature", Info.Signature, 0);
2717429d86fSPavel Labath   mapOptionalHex(IO, "Struct Version", Info.StructVersion, 0);
2727429d86fSPavel Labath   mapOptionalHex(IO, "File Version High", Info.FileVersionHigh, 0);
2737429d86fSPavel Labath   mapOptionalHex(IO, "File Version Low", Info.FileVersionLow, 0);
2747429d86fSPavel Labath   mapOptionalHex(IO, "Product Version High", Info.ProductVersionHigh, 0);
2757429d86fSPavel Labath   mapOptionalHex(IO, "Product Version Low", Info.ProductVersionLow, 0);
2767429d86fSPavel Labath   mapOptionalHex(IO, "File Flags Mask", Info.FileFlagsMask, 0);
2777429d86fSPavel Labath   mapOptionalHex(IO, "File Flags", Info.FileFlags, 0);
2787429d86fSPavel Labath   mapOptionalHex(IO, "File OS", Info.FileOS, 0);
2797429d86fSPavel Labath   mapOptionalHex(IO, "File Type", Info.FileType, 0);
2807429d86fSPavel Labath   mapOptionalHex(IO, "File Subtype", Info.FileSubtype, 0);
2817429d86fSPavel Labath   mapOptionalHex(IO, "File Date High", Info.FileDateHigh, 0);
2827429d86fSPavel Labath   mapOptionalHex(IO, "File Date Low", Info.FileDateLow, 0);
2837429d86fSPavel Labath }
2847429d86fSPavel Labath 
285dcdb3c66SPavel Labath void yaml::MappingTraits<ModuleListStream::entry_type>::mapping(
286dcdb3c66SPavel Labath     IO &IO, ModuleListStream::entry_type &M) {
287dcdb3c66SPavel Labath   mapRequiredHex(IO, "Base of Image", M.Entry.BaseOfImage);
288dcdb3c66SPavel Labath   mapRequiredHex(IO, "Size of Image", M.Entry.SizeOfImage);
289dcdb3c66SPavel Labath   mapOptionalHex(IO, "Checksum", M.Entry.Checksum, 0);
290a50272f8SJoseph Tremoulet   mapOptional(IO, "Time Date Stamp", M.Entry.TimeDateStamp, 0);
2917429d86fSPavel Labath   IO.mapRequired("Module Name", M.Name);
292dcdb3c66SPavel Labath   IO.mapOptional("Version Info", M.Entry.VersionInfo, VSFixedFileInfo());
2937429d86fSPavel Labath   IO.mapRequired("CodeView Record", M.CvRecord);
2947429d86fSPavel Labath   IO.mapOptional("Misc Record", M.MiscRecord, yaml::BinaryRef());
295dcdb3c66SPavel Labath   mapOptionalHex(IO, "Reserved0", M.Entry.Reserved0, 0);
296dcdb3c66SPavel Labath   mapOptionalHex(IO, "Reserved1", M.Entry.Reserved1, 0);
2977429d86fSPavel Labath }
2987429d86fSPavel Labath 
29969de7a95SPavel Labath static void streamMapping(yaml::IO &IO, RawContentStream &Stream) {
30069de7a95SPavel Labath   IO.mapOptional("Content", Stream.Content);
30169de7a95SPavel Labath   IO.mapOptional("Size", Stream.Size, Stream.Content.binary_size());
30269de7a95SPavel Labath }
30369de7a95SPavel Labath 
3046487ffafSGeorgii Rymar static std::string streamValidate(RawContentStream &Stream) {
30569de7a95SPavel Labath   if (Stream.Size.value < Stream.Content.binary_size())
30669de7a95SPavel Labath     return "Stream size must be greater or equal to the content size";
30769de7a95SPavel Labath   return "";
30869de7a95SPavel Labath }
30969de7a95SPavel Labath 
3102d29e16cSPavel Labath void yaml::MappingTraits<MemoryListStream::entry_type>::mapping(
3112d29e16cSPavel Labath     IO &IO, MemoryListStream::entry_type &Range) {
3122d29e16cSPavel Labath   MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
3132d29e16cSPavel Labath       IO, Range.Entry, Range.Content);
3142d29e16cSPavel Labath }
3152d29e16cSPavel Labath 
3163aa7e766SPavel Labath static void streamMapping(yaml::IO &IO, MemoryInfoListStream &Stream) {
3173aa7e766SPavel Labath   IO.mapRequired("Memory Ranges", Stream.Infos);
3183aa7e766SPavel Labath }
3193aa7e766SPavel Labath 
3202d29e16cSPavel Labath static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) {
3212d29e16cSPavel Labath   IO.mapRequired("Memory Ranges", Stream.Entries);
3222d29e16cSPavel Labath }
3232d29e16cSPavel Labath 
324b1edac04SJacob Lalonde static void streamMapping(yaml::IO &IO, Memory64ListStream &Stream) {
325b1edac04SJacob Lalonde   IO.mapRequired("Memory Ranges", Stream.Entries);
326b1edac04SJacob Lalonde }
327b1edac04SJacob Lalonde 
328b1edac04SJacob Lalonde static std::string streamValidate(Memory64ListStream &Stream) {
329b1edac04SJacob Lalonde   for (auto &Entry : Stream.Entries) {
330b1edac04SJacob Lalonde     if (Entry.Entry.DataSize < Entry.Content.binary_size())
331b1edac04SJacob Lalonde       return "Memory region size must be greater or equal to the content size";
332b1edac04SJacob Lalonde   }
333b1edac04SJacob Lalonde   return "";
334b1edac04SJacob Lalonde }
335b1edac04SJacob Lalonde 
3367429d86fSPavel Labath static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) {
337dcdb3c66SPavel Labath   IO.mapRequired("Modules", Stream.Entries);
3387429d86fSPavel Labath }
3397429d86fSPavel Labath 
34069de7a95SPavel Labath static void streamMapping(yaml::IO &IO, SystemInfoStream &Stream) {
34169de7a95SPavel Labath   SystemInfo &Info = Stream.Info;
34269de7a95SPavel Labath   IO.mapRequired("Processor Arch", Info.ProcessorArch);
34369de7a95SPavel Labath   mapOptional(IO, "Processor Level", Info.ProcessorLevel, 0);
34469de7a95SPavel Labath   mapOptional(IO, "Processor Revision", Info.ProcessorRevision, 0);
34569de7a95SPavel Labath   IO.mapOptional("Number of Processors", Info.NumberOfProcessors, 0);
34669de7a95SPavel Labath   IO.mapOptional("Product type", Info.ProductType, 0);
34769de7a95SPavel Labath   mapOptional(IO, "Major Version", Info.MajorVersion, 0);
34869de7a95SPavel Labath   mapOptional(IO, "Minor Version", Info.MinorVersion, 0);
34969de7a95SPavel Labath   mapOptional(IO, "Build Number", Info.BuildNumber, 0);
35069de7a95SPavel Labath   IO.mapRequired("Platform ID", Info.PlatformId);
35151d9fa0aSPavel Labath   IO.mapOptional("CSD Version", Stream.CSDVersion, "");
35269de7a95SPavel Labath   mapOptionalHex(IO, "Suite Mask", Info.SuiteMask, 0);
35369de7a95SPavel Labath   mapOptionalHex(IO, "Reserved", Info.Reserved, 0);
35469de7a95SPavel Labath   switch (static_cast<ProcessorArchitecture>(Info.ProcessorArch)) {
35569de7a95SPavel Labath   case ProcessorArchitecture::X86:
35669de7a95SPavel Labath   case ProcessorArchitecture::AMD64:
35769de7a95SPavel Labath     IO.mapOptional("CPU", Info.CPU.X86);
35869de7a95SPavel Labath     break;
35969de7a95SPavel Labath   case ProcessorArchitecture::ARM:
360e9430231SPavel Labath   case ProcessorArchitecture::ARM64:
36183a55c6aSPavel Labath   case ProcessorArchitecture::BP_ARM64:
36269de7a95SPavel Labath     IO.mapOptional("CPU", Info.CPU.Arm);
36369de7a95SPavel Labath     break;
36469de7a95SPavel Labath   default:
36569de7a95SPavel Labath     IO.mapOptional("CPU", Info.CPU.Other);
36669de7a95SPavel Labath     break;
36769de7a95SPavel Labath   }
36869de7a95SPavel Labath }
36969de7a95SPavel Labath 
37069de7a95SPavel Labath static void streamMapping(yaml::IO &IO, TextContentStream &Stream) {
37169de7a95SPavel Labath   IO.mapOptional("Text", Stream.Text);
37269de7a95SPavel Labath }
37369de7a95SPavel Labath 
374dcdb3c66SPavel Labath void yaml::MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
375dcdb3c66SPavel Labath     IO &IO, MemoryDescriptor &Memory, BinaryRef &Content) {
376dcdb3c66SPavel Labath   mapRequiredHex(IO, "Start of Memory Range", Memory.StartOfMemoryRange);
377dcdb3c66SPavel Labath   IO.mapRequired("Content", Content);
378dcdb3c66SPavel Labath }
379dcdb3c66SPavel Labath 
380b1edac04SJacob Lalonde void yaml::MappingContextTraits<MemoryDescriptor_64, yaml::BinaryRef>::mapping(
381b1edac04SJacob Lalonde     IO &IO, MemoryDescriptor_64 &Memory, BinaryRef &Content) {
382b1edac04SJacob Lalonde   mapRequiredHex(IO, "Start of Memory Range", Memory.StartOfMemoryRange);
383b1edac04SJacob Lalonde   IO.mapRequired("Content", Content);
384b1edac04SJacob Lalonde   mapOptional(IO, "Data Size", Memory.DataSize, Content.binary_size());
385b1edac04SJacob Lalonde }
386b1edac04SJacob Lalonde 
387dcdb3c66SPavel Labath void yaml::MappingTraits<ThreadListStream::entry_type>::mapping(
388dcdb3c66SPavel Labath     IO &IO, ThreadListStream::entry_type &T) {
389dcdb3c66SPavel Labath   mapRequiredHex(IO, "Thread Id", T.Entry.ThreadId);
390dcdb3c66SPavel Labath   mapOptionalHex(IO, "Suspend Count", T.Entry.SuspendCount, 0);
391dcdb3c66SPavel Labath   mapOptionalHex(IO, "Priority Class", T.Entry.PriorityClass, 0);
392dcdb3c66SPavel Labath   mapOptionalHex(IO, "Priority", T.Entry.Priority, 0);
393dcdb3c66SPavel Labath   mapOptionalHex(IO, "Environment Block", T.Entry.EnvironmentBlock, 0);
394dcdb3c66SPavel Labath   IO.mapRequired("Context", T.Context);
395dcdb3c66SPavel Labath   IO.mapRequired("Stack", T.Entry.Stack, T.Stack);
396dcdb3c66SPavel Labath }
397dcdb3c66SPavel Labath 
398dcdb3c66SPavel Labath static void streamMapping(yaml::IO &IO, ThreadListStream &Stream) {
399dcdb3c66SPavel Labath   IO.mapRequired("Threads", Stream.Entries);
400dcdb3c66SPavel Labath }
401dcdb3c66SPavel Labath 
402a50272f8SJoseph Tremoulet static void streamMapping(yaml::IO &IO, MinidumpYAML::ExceptionStream &Stream) {
403a50272f8SJoseph Tremoulet   mapRequiredHex(IO, "Thread ID", Stream.MDExceptionStream.ThreadId);
404a50272f8SJoseph Tremoulet   IO.mapRequired("Exception Record", Stream.MDExceptionStream.ExceptionRecord);
405a50272f8SJoseph Tremoulet   IO.mapRequired("Thread Context", Stream.ThreadContext);
406a50272f8SJoseph Tremoulet }
407a50272f8SJoseph Tremoulet 
408a50272f8SJoseph Tremoulet void yaml::MappingTraits<minidump::Exception>::mapping(
409a50272f8SJoseph Tremoulet     yaml::IO &IO, minidump::Exception &Exception) {
410a50272f8SJoseph Tremoulet   mapRequiredHex(IO, "Exception Code", Exception.ExceptionCode);
411a50272f8SJoseph Tremoulet   mapOptionalHex(IO, "Exception Flags", Exception.ExceptionFlags, 0);
412a50272f8SJoseph Tremoulet   mapOptionalHex(IO, "Exception Record", Exception.ExceptionRecord, 0);
413a50272f8SJoseph Tremoulet   mapOptionalHex(IO, "Exception Address", Exception.ExceptionAddress, 0);
414a50272f8SJoseph Tremoulet   mapOptional(IO, "Number of Parameters", Exception.NumberParameters, 0);
415a50272f8SJoseph Tremoulet 
416a50272f8SJoseph Tremoulet   for (size_t Index = 0; Index < Exception.MaxParameters; ++Index) {
417a50272f8SJoseph Tremoulet     SmallString<16> Name("Parameter ");
418a50272f8SJoseph Tremoulet     Twine(Index).toVector(Name);
419a50272f8SJoseph Tremoulet     support::ulittle64_t &Field = Exception.ExceptionInformation[Index];
420a50272f8SJoseph Tremoulet 
421a50272f8SJoseph Tremoulet     if (Index < Exception.NumberParameters)
422a50272f8SJoseph Tremoulet       mapRequiredHex(IO, Name.c_str(), Field);
423a50272f8SJoseph Tremoulet     else
424a50272f8SJoseph Tremoulet       mapOptionalHex(IO, Name.c_str(), Field, 0);
425a50272f8SJoseph Tremoulet   }
426a50272f8SJoseph Tremoulet }
427a50272f8SJoseph Tremoulet 
42869de7a95SPavel Labath void yaml::MappingTraits<std::unique_ptr<Stream>>::mapping(
42969de7a95SPavel Labath     yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) {
43069de7a95SPavel Labath   StreamType Type;
43169de7a95SPavel Labath   if (IO.outputting())
43269de7a95SPavel Labath     Type = S->Type;
43369de7a95SPavel Labath   IO.mapRequired("Type", Type);
43469de7a95SPavel Labath 
43569de7a95SPavel Labath   if (!IO.outputting())
43669de7a95SPavel Labath     S = MinidumpYAML::Stream::create(Type);
43769de7a95SPavel Labath   switch (S->Kind) {
438a50272f8SJoseph Tremoulet   case MinidumpYAML::Stream::StreamKind::Exception:
439a50272f8SJoseph Tremoulet     streamMapping(IO, llvm::cast<MinidumpYAML::ExceptionStream>(*S));
440a50272f8SJoseph Tremoulet     break;
4413aa7e766SPavel Labath   case MinidumpYAML::Stream::StreamKind::MemoryInfoList:
4423aa7e766SPavel Labath     streamMapping(IO, llvm::cast<MemoryInfoListStream>(*S));
4433aa7e766SPavel Labath     break;
4442d29e16cSPavel Labath   case MinidumpYAML::Stream::StreamKind::MemoryList:
4452d29e16cSPavel Labath     streamMapping(IO, llvm::cast<MemoryListStream>(*S));
4462d29e16cSPavel Labath     break;
447b1edac04SJacob Lalonde   case MinidumpYAML::Stream::StreamKind::Memory64List:
448b1edac04SJacob Lalonde     streamMapping(IO, llvm::cast<Memory64ListStream>(*S));
449b1edac04SJacob Lalonde     break;
4507429d86fSPavel Labath   case MinidumpYAML::Stream::StreamKind::ModuleList:
4517429d86fSPavel Labath     streamMapping(IO, llvm::cast<ModuleListStream>(*S));
4527429d86fSPavel Labath     break;
45369de7a95SPavel Labath   case MinidumpYAML::Stream::StreamKind::RawContent:
45469de7a95SPavel Labath     streamMapping(IO, llvm::cast<RawContentStream>(*S));
45569de7a95SPavel Labath     break;
45669de7a95SPavel Labath   case MinidumpYAML::Stream::StreamKind::SystemInfo:
45769de7a95SPavel Labath     streamMapping(IO, llvm::cast<SystemInfoStream>(*S));
45869de7a95SPavel Labath     break;
45969de7a95SPavel Labath   case MinidumpYAML::Stream::StreamKind::TextContent:
46069de7a95SPavel Labath     streamMapping(IO, llvm::cast<TextContentStream>(*S));
46169de7a95SPavel Labath     break;
462dcdb3c66SPavel Labath   case MinidumpYAML::Stream::StreamKind::ThreadList:
463dcdb3c66SPavel Labath     streamMapping(IO, llvm::cast<ThreadListStream>(*S));
464dcdb3c66SPavel Labath     break;
46569de7a95SPavel Labath   }
46669de7a95SPavel Labath }
46769de7a95SPavel Labath 
4686487ffafSGeorgii Rymar std::string yaml::MappingTraits<std::unique_ptr<Stream>>::validate(
46969de7a95SPavel Labath     yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) {
47069de7a95SPavel Labath   switch (S->Kind) {
47169de7a95SPavel Labath   case MinidumpYAML::Stream::StreamKind::RawContent:
47269de7a95SPavel Labath     return streamValidate(cast<RawContentStream>(*S));
473b1edac04SJacob Lalonde   case MinidumpYAML::Stream::StreamKind::Memory64List:
474b1edac04SJacob Lalonde     return streamValidate(cast<Memory64ListStream>(*S));
475a50272f8SJoseph Tremoulet   case MinidumpYAML::Stream::StreamKind::Exception:
4763aa7e766SPavel Labath   case MinidumpYAML::Stream::StreamKind::MemoryInfoList:
4772d29e16cSPavel Labath   case MinidumpYAML::Stream::StreamKind::MemoryList:
4787429d86fSPavel Labath   case MinidumpYAML::Stream::StreamKind::ModuleList:
47969de7a95SPavel Labath   case MinidumpYAML::Stream::StreamKind::SystemInfo:
48069de7a95SPavel Labath   case MinidumpYAML::Stream::StreamKind::TextContent:
481dcdb3c66SPavel Labath   case MinidumpYAML::Stream::StreamKind::ThreadList:
48269de7a95SPavel Labath     return "";
48369de7a95SPavel Labath   }
48469de7a95SPavel Labath   llvm_unreachable("Fully covered switch above!");
48569de7a95SPavel Labath }
48669de7a95SPavel Labath 
48769de7a95SPavel Labath void yaml::MappingTraits<Object>::mapping(IO &IO, Object &O) {
48869de7a95SPavel Labath   IO.mapTag("!minidump", true);
48969de7a95SPavel Labath   mapOptionalHex(IO, "Signature", O.Header.Signature, Header::MagicSignature);
49069de7a95SPavel Labath   mapOptionalHex(IO, "Version", O.Header.Version, Header::MagicVersion);
49169de7a95SPavel Labath   mapOptionalHex(IO, "Flags", O.Header.Flags, 0);
49269de7a95SPavel Labath   IO.mapRequired("Streams", O.Streams);
49369de7a95SPavel Labath }
49469de7a95SPavel Labath 
4953cee663eSPavel Labath Expected<std::unique_ptr<Stream>>
4963cee663eSPavel Labath Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
4973cee663eSPavel Labath   StreamKind Kind = getKind(StreamDesc.Type);
4983cee663eSPavel Labath   switch (Kind) {
499a50272f8SJoseph Tremoulet   case StreamKind::Exception: {
500a50272f8SJoseph Tremoulet     Expected<const minidump::ExceptionStream &> ExpectedExceptionStream =
501*deba1340SJacob Lalonde         File.getExceptionStream(StreamDesc);
502a50272f8SJoseph Tremoulet     if (!ExpectedExceptionStream)
503a50272f8SJoseph Tremoulet       return ExpectedExceptionStream.takeError();
504a50272f8SJoseph Tremoulet     Expected<ArrayRef<uint8_t>> ExpectedThreadContext =
505a50272f8SJoseph Tremoulet         File.getRawData(ExpectedExceptionStream->ThreadContext);
506a50272f8SJoseph Tremoulet     if (!ExpectedThreadContext)
507a50272f8SJoseph Tremoulet       return ExpectedThreadContext.takeError();
508a50272f8SJoseph Tremoulet     return std::make_unique<ExceptionStream>(*ExpectedExceptionStream,
509a50272f8SJoseph Tremoulet                                              *ExpectedThreadContext);
510a50272f8SJoseph Tremoulet   }
5113aa7e766SPavel Labath   case StreamKind::MemoryInfoList: {
5123aa7e766SPavel Labath     if (auto ExpectedList = File.getMemoryInfoList())
5133aa7e766SPavel Labath       return std::make_unique<MemoryInfoListStream>(*ExpectedList);
5143aa7e766SPavel Labath     else
5153aa7e766SPavel Labath       return ExpectedList.takeError();
5163aa7e766SPavel Labath   }
5172d29e16cSPavel Labath   case StreamKind::MemoryList: {
5182d29e16cSPavel Labath     auto ExpectedList = File.getMemoryList();
5192d29e16cSPavel Labath     if (!ExpectedList)
5202d29e16cSPavel Labath       return ExpectedList.takeError();
5212d29e16cSPavel Labath     std::vector<MemoryListStream::entry_type> Ranges;
5222d29e16cSPavel Labath     for (const MemoryDescriptor &MD : *ExpectedList) {
5232d29e16cSPavel Labath       auto ExpectedContent = File.getRawData(MD.Memory);
5242d29e16cSPavel Labath       if (!ExpectedContent)
5252d29e16cSPavel Labath         return ExpectedContent.takeError();
5262d29e16cSPavel Labath       Ranges.push_back({MD, *ExpectedContent});
5272d29e16cSPavel Labath     }
5280eaee545SJonas Devlieghere     return std::make_unique<MemoryListStream>(std::move(Ranges));
5292d29e16cSPavel Labath   }
530b1edac04SJacob Lalonde   case StreamKind::Memory64List: {
531b1edac04SJacob Lalonde     Error Err = Error::success();
532b1edac04SJacob Lalonde     auto Memory64List = File.getMemory64List(Err);
533b1edac04SJacob Lalonde     std::vector<Memory64ListStream::entry_type> Ranges;
534b1edac04SJacob Lalonde     for (const auto &Pair : Memory64List) {
535b1edac04SJacob Lalonde       Ranges.push_back({Pair.first, Pair.second});
536b1edac04SJacob Lalonde     }
537b1edac04SJacob Lalonde 
538b1edac04SJacob Lalonde     if (Err)
539b1edac04SJacob Lalonde       return Err;
540b1edac04SJacob Lalonde     return std::make_unique<Memory64ListStream>(std::move(Ranges));
541b1edac04SJacob Lalonde   }
5427429d86fSPavel Labath   case StreamKind::ModuleList: {
5437429d86fSPavel Labath     auto ExpectedList = File.getModuleList();
5447429d86fSPavel Labath     if (!ExpectedList)
5457429d86fSPavel Labath       return ExpectedList.takeError();
546dcdb3c66SPavel Labath     std::vector<ModuleListStream::entry_type> Modules;
5477429d86fSPavel Labath     for (const Module &M : *ExpectedList) {
5487429d86fSPavel Labath       auto ExpectedName = File.getString(M.ModuleNameRVA);
5497429d86fSPavel Labath       if (!ExpectedName)
5507429d86fSPavel Labath         return ExpectedName.takeError();
5517429d86fSPavel Labath       auto ExpectedCv = File.getRawData(M.CvRecord);
5527429d86fSPavel Labath       if (!ExpectedCv)
5537429d86fSPavel Labath         return ExpectedCv.takeError();
5547429d86fSPavel Labath       auto ExpectedMisc = File.getRawData(M.MiscRecord);
5557429d86fSPavel Labath       if (!ExpectedMisc)
5567429d86fSPavel Labath         return ExpectedMisc.takeError();
5577429d86fSPavel Labath       Modules.push_back(
5587429d86fSPavel Labath           {M, std::move(*ExpectedName), *ExpectedCv, *ExpectedMisc});
5597429d86fSPavel Labath     }
5600eaee545SJonas Devlieghere     return std::make_unique<ModuleListStream>(std::move(Modules));
5617429d86fSPavel Labath   }
5623cee663eSPavel Labath   case StreamKind::RawContent:
5630eaee545SJonas Devlieghere     return std::make_unique<RawContentStream>(StreamDesc.Type,
5643cee663eSPavel Labath                                                File.getRawStream(StreamDesc));
5653cee663eSPavel Labath   case StreamKind::SystemInfo: {
5663cee663eSPavel Labath     auto ExpectedInfo = File.getSystemInfo();
5673cee663eSPavel Labath     if (!ExpectedInfo)
5683cee663eSPavel Labath       return ExpectedInfo.takeError();
56951d9fa0aSPavel Labath     auto ExpectedCSDVersion = File.getString(ExpectedInfo->CSDVersionRVA);
57051d9fa0aSPavel Labath     if (!ExpectedCSDVersion)
57151d9fa0aSPavel Labath       return ExpectedInfo.takeError();
5720eaee545SJonas Devlieghere     return std::make_unique<SystemInfoStream>(*ExpectedInfo,
57351d9fa0aSPavel Labath                                                std::move(*ExpectedCSDVersion));
5743cee663eSPavel Labath   }
5753cee663eSPavel Labath   case StreamKind::TextContent:
5760eaee545SJonas Devlieghere     return std::make_unique<TextContentStream>(
5773cee663eSPavel Labath         StreamDesc.Type, toStringRef(File.getRawStream(StreamDesc)));
578dcdb3c66SPavel Labath   case StreamKind::ThreadList: {
579dcdb3c66SPavel Labath     auto ExpectedList = File.getThreadList();
580dcdb3c66SPavel Labath     if (!ExpectedList)
581dcdb3c66SPavel Labath       return ExpectedList.takeError();
582dcdb3c66SPavel Labath     std::vector<ThreadListStream::entry_type> Threads;
583dcdb3c66SPavel Labath     for (const Thread &T : *ExpectedList) {
584dcdb3c66SPavel Labath       auto ExpectedStack = File.getRawData(T.Stack.Memory);
585dcdb3c66SPavel Labath       if (!ExpectedStack)
586dcdb3c66SPavel Labath         return ExpectedStack.takeError();
587dcdb3c66SPavel Labath       auto ExpectedContext = File.getRawData(T.Context);
588dcdb3c66SPavel Labath       if (!ExpectedContext)
589dcdb3c66SPavel Labath         return ExpectedContext.takeError();
590dcdb3c66SPavel Labath       Threads.push_back({T, *ExpectedStack, *ExpectedContext});
591dcdb3c66SPavel Labath     }
5920eaee545SJonas Devlieghere     return std::make_unique<ThreadListStream>(std::move(Threads));
593dcdb3c66SPavel Labath   }
5943cee663eSPavel Labath   }
5953cee663eSPavel Labath   llvm_unreachable("Unhandled stream kind!");
5963cee663eSPavel Labath }
5973cee663eSPavel Labath 
5983cee663eSPavel Labath Expected<Object> Object::create(const object::MinidumpFile &File) {
5993cee663eSPavel Labath   std::vector<std::unique_ptr<Stream>> Streams;
6003cee663eSPavel Labath   Streams.reserve(File.streams().size());
6013cee663eSPavel Labath   for (const Directory &StreamDesc : File.streams()) {
6023cee663eSPavel Labath     auto ExpectedStream = Stream::create(StreamDesc, File);
6033cee663eSPavel Labath     if (!ExpectedStream)
6043cee663eSPavel Labath       return ExpectedStream.takeError();
6053cee663eSPavel Labath     Streams.push_back(std::move(*ExpectedStream));
6063cee663eSPavel Labath   }
6073cee663eSPavel Labath   return Object(File.header(), std::move(Streams));
6083cee663eSPavel Labath }
609