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