MinidumpYAML.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. //===- MinidumpYAML.cpp - Minidump YAMLIO implementation ------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/ObjectYAML/MinidumpYAML.h"
  9. #include "llvm/Support/Allocator.h"
  10. using namespace llvm;
  11. using namespace llvm::MinidumpYAML;
  12. using namespace llvm::minidump;
  13. /// Perform an optional yaml-mapping of an endian-aware type EndianType. The
  14. /// only purpose of this function is to avoid casting the Default value to the
  15. /// endian type;
  16. template <typename EndianType>
  17. static inline void mapOptional(yaml::IO &IO, const char *Key, EndianType &Val,
  18. typename EndianType::value_type Default) {
  19. IO.mapOptional(Key, Val, EndianType(Default));
  20. }
  21. /// Yaml-map an endian-aware type EndianType as some other type MapType.
  22. template <typename MapType, typename EndianType>
  23. static inline void mapRequiredAs(yaml::IO &IO, const char *Key,
  24. EndianType &Val) {
  25. MapType Mapped = static_cast<typename EndianType::value_type>(Val);
  26. IO.mapRequired(Key, Mapped);
  27. Val = static_cast<typename EndianType::value_type>(Mapped);
  28. }
  29. /// Perform an optional yaml-mapping of an endian-aware type EndianType as some
  30. /// other type MapType.
  31. template <typename MapType, typename EndianType>
  32. static inline void mapOptionalAs(yaml::IO &IO, const char *Key, EndianType &Val,
  33. MapType Default) {
  34. MapType Mapped = static_cast<typename EndianType::value_type>(Val);
  35. IO.mapOptional(Key, Mapped, Default);
  36. Val = static_cast<typename EndianType::value_type>(Mapped);
  37. }
  38. namespace {
  39. /// Return the appropriate yaml Hex type for a given endian-aware type.
  40. template <typename EndianType> struct HexType;
  41. template <> struct HexType<support::ulittle16_t> { using type = yaml::Hex16; };
  42. template <> struct HexType<support::ulittle32_t> { using type = yaml::Hex32; };
  43. template <> struct HexType<support::ulittle64_t> { using type = yaml::Hex64; };
  44. } // namespace
  45. /// Yaml-map an endian-aware type as an appropriately-sized hex value.
  46. template <typename EndianType>
  47. static inline void mapRequiredHex(yaml::IO &IO, const char *Key,
  48. EndianType &Val) {
  49. mapRequiredAs<typename HexType<EndianType>::type>(IO, Key, Val);
  50. }
  51. /// Perform an optional yaml-mapping of an endian-aware type as an
  52. /// appropriately-sized hex value.
  53. template <typename EndianType>
  54. static inline void mapOptionalHex(yaml::IO &IO, const char *Key,
  55. EndianType &Val,
  56. typename EndianType::value_type Default) {
  57. mapOptionalAs<typename HexType<EndianType>::type>(IO, Key, Val, Default);
  58. }
  59. Stream::~Stream() = default;
  60. Stream::StreamKind Stream::getKind(StreamType Type) {
  61. switch (Type) {
  62. case StreamType::Exception:
  63. return StreamKind::Exception;
  64. case StreamType::MemoryInfoList:
  65. return StreamKind::MemoryInfoList;
  66. case StreamType::MemoryList:
  67. return StreamKind::MemoryList;
  68. case StreamType::ModuleList:
  69. return StreamKind::ModuleList;
  70. case StreamType::SystemInfo:
  71. return StreamKind::SystemInfo;
  72. case StreamType::LinuxCPUInfo:
  73. case StreamType::LinuxProcStatus:
  74. case StreamType::LinuxLSBRelease:
  75. case StreamType::LinuxCMDLine:
  76. case StreamType::LinuxMaps:
  77. case StreamType::LinuxProcStat:
  78. case StreamType::LinuxProcUptime:
  79. return StreamKind::TextContent;
  80. case StreamType::ThreadList:
  81. return StreamKind::ThreadList;
  82. default:
  83. return StreamKind::RawContent;
  84. }
  85. }
  86. std::unique_ptr<Stream> Stream::create(StreamType Type) {
  87. StreamKind Kind = getKind(Type);
  88. switch (Kind) {
  89. case StreamKind::Exception:
  90. return std::make_unique<ExceptionStream>();
  91. case StreamKind::MemoryInfoList:
  92. return std::make_unique<MemoryInfoListStream>();
  93. case StreamKind::MemoryList:
  94. return std::make_unique<MemoryListStream>();
  95. case StreamKind::ModuleList:
  96. return std::make_unique<ModuleListStream>();
  97. case StreamKind::RawContent:
  98. return std::make_unique<RawContentStream>(Type);
  99. case StreamKind::SystemInfo:
  100. return std::make_unique<SystemInfoStream>();
  101. case StreamKind::TextContent:
  102. return std::make_unique<TextContentStream>(Type);
  103. case StreamKind::ThreadList:
  104. return std::make_unique<ThreadListStream>();
  105. }
  106. llvm_unreachable("Unhandled stream kind!");
  107. }
  108. void yaml::ScalarBitSetTraits<MemoryProtection>::bitset(
  109. IO &IO, MemoryProtection &Protect) {
  110. #define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME) \
  111. IO.bitSetCase(Protect, #NATIVENAME, MemoryProtection::NAME);
  112. #include "llvm/BinaryFormat/MinidumpConstants.def"
  113. }
  114. void yaml::ScalarBitSetTraits<MemoryState>::bitset(IO &IO, MemoryState &State) {
  115. #define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME) \
  116. IO.bitSetCase(State, #NATIVENAME, MemoryState::NAME);
  117. #include "llvm/BinaryFormat/MinidumpConstants.def"
  118. }
  119. void yaml::ScalarBitSetTraits<MemoryType>::bitset(IO &IO, MemoryType &Type) {
  120. #define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME) \
  121. IO.bitSetCase(Type, #NATIVENAME, MemoryType::NAME);
  122. #include "llvm/BinaryFormat/MinidumpConstants.def"
  123. }
  124. void yaml::ScalarEnumerationTraits<ProcessorArchitecture>::enumeration(
  125. IO &IO, ProcessorArchitecture &Arch) {
  126. #define HANDLE_MDMP_ARCH(CODE, NAME) \
  127. IO.enumCase(Arch, #NAME, ProcessorArchitecture::NAME);
  128. #include "llvm/BinaryFormat/MinidumpConstants.def"
  129. IO.enumFallback<Hex16>(Arch);
  130. }
  131. void yaml::ScalarEnumerationTraits<OSPlatform>::enumeration(IO &IO,
  132. OSPlatform &Plat) {
  133. #define HANDLE_MDMP_PLATFORM(CODE, NAME) \
  134. IO.enumCase(Plat, #NAME, OSPlatform::NAME);
  135. #include "llvm/BinaryFormat/MinidumpConstants.def"
  136. IO.enumFallback<Hex32>(Plat);
  137. }
  138. void yaml::ScalarEnumerationTraits<StreamType>::enumeration(IO &IO,
  139. StreamType &Type) {
  140. #define HANDLE_MDMP_STREAM_TYPE(CODE, NAME) \
  141. IO.enumCase(Type, #NAME, StreamType::NAME);
  142. #include "llvm/BinaryFormat/MinidumpConstants.def"
  143. IO.enumFallback<Hex32>(Type);
  144. }
  145. void yaml::MappingTraits<CPUInfo::ArmInfo>::mapping(IO &IO,
  146. CPUInfo::ArmInfo &Info) {
  147. mapRequiredHex(IO, "CPUID", Info.CPUID);
  148. mapOptionalHex(IO, "ELF hwcaps", Info.ElfHWCaps, 0);
  149. }
  150. namespace {
  151. template <std::size_t N> struct FixedSizeHex {
  152. FixedSizeHex(uint8_t (&Storage)[N]) : Storage(Storage) {}
  153. uint8_t (&Storage)[N];
  154. };
  155. } // namespace
  156. namespace llvm {
  157. namespace yaml {
  158. template <std::size_t N> struct ScalarTraits<FixedSizeHex<N>> {
  159. static void output(const FixedSizeHex<N> &Fixed, void *, raw_ostream &OS) {
  160. OS << toHex(ArrayRef(Fixed.Storage));
  161. }
  162. static StringRef input(StringRef Scalar, void *, FixedSizeHex<N> &Fixed) {
  163. if (!all_of(Scalar, isHexDigit))
  164. return "Invalid hex digit in input";
  165. if (Scalar.size() < 2 * N)
  166. return "String too short";
  167. if (Scalar.size() > 2 * N)
  168. return "String too long";
  169. copy(fromHex(Scalar), Fixed.Storage);
  170. return "";
  171. }
  172. static QuotingType mustQuote(StringRef S) { return QuotingType::None; }
  173. };
  174. } // namespace yaml
  175. } // namespace llvm
  176. void yaml::MappingTraits<CPUInfo::OtherInfo>::mapping(
  177. IO &IO, CPUInfo::OtherInfo &Info) {
  178. FixedSizeHex<sizeof(Info.ProcessorFeatures)> Features(Info.ProcessorFeatures);
  179. IO.mapRequired("Features", Features);
  180. }
  181. namespace {
  182. /// A type which only accepts strings of a fixed size for yaml conversion.
  183. template <std::size_t N> struct FixedSizeString {
  184. FixedSizeString(char (&Storage)[N]) : Storage(Storage) {}
  185. char (&Storage)[N];
  186. };
  187. } // namespace
  188. namespace llvm {
  189. namespace yaml {
  190. template <std::size_t N> struct ScalarTraits<FixedSizeString<N>> {
  191. static void output(const FixedSizeString<N> &Fixed, void *, raw_ostream &OS) {
  192. OS << StringRef(Fixed.Storage, N);
  193. }
  194. static StringRef input(StringRef Scalar, void *, FixedSizeString<N> &Fixed) {
  195. if (Scalar.size() < N)
  196. return "String too short";
  197. if (Scalar.size() > N)
  198. return "String too long";
  199. copy(Scalar, Fixed.Storage);
  200. return "";
  201. }
  202. static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
  203. };
  204. } // namespace yaml
  205. } // namespace llvm
  206. void yaml::MappingTraits<CPUInfo::X86Info>::mapping(IO &IO,
  207. CPUInfo::X86Info &Info) {
  208. FixedSizeString<sizeof(Info.VendorID)> VendorID(Info.VendorID);
  209. IO.mapRequired("Vendor ID", VendorID);
  210. mapRequiredHex(IO, "Version Info", Info.VersionInfo);
  211. mapRequiredHex(IO, "Feature Info", Info.FeatureInfo);
  212. mapOptionalHex(IO, "AMD Extended Features", Info.AMDExtendedFeatures, 0);
  213. }
  214. void yaml::MappingTraits<MemoryInfo>::mapping(IO &IO, MemoryInfo &Info) {
  215. mapRequiredHex(IO, "Base Address", Info.BaseAddress);
  216. mapOptionalHex(IO, "Allocation Base", Info.AllocationBase, Info.BaseAddress);
  217. mapRequiredAs<MemoryProtection>(IO, "Allocation Protect",
  218. Info.AllocationProtect);
  219. mapOptionalHex(IO, "Reserved0", Info.Reserved0, 0);
  220. mapRequiredHex(IO, "Region Size", Info.RegionSize);
  221. mapRequiredAs<MemoryState>(IO, "State", Info.State);
  222. mapOptionalAs<MemoryProtection>(IO, "Protect", Info.Protect,
  223. Info.AllocationProtect);
  224. mapRequiredAs<MemoryType>(IO, "Type", Info.Type);
  225. mapOptionalHex(IO, "Reserved1", Info.Reserved1, 0);
  226. }
  227. void yaml::MappingTraits<VSFixedFileInfo>::mapping(IO &IO,
  228. VSFixedFileInfo &Info) {
  229. mapOptionalHex(IO, "Signature", Info.Signature, 0);
  230. mapOptionalHex(IO, "Struct Version", Info.StructVersion, 0);
  231. mapOptionalHex(IO, "File Version High", Info.FileVersionHigh, 0);
  232. mapOptionalHex(IO, "File Version Low", Info.FileVersionLow, 0);
  233. mapOptionalHex(IO, "Product Version High", Info.ProductVersionHigh, 0);
  234. mapOptionalHex(IO, "Product Version Low", Info.ProductVersionLow, 0);
  235. mapOptionalHex(IO, "File Flags Mask", Info.FileFlagsMask, 0);
  236. mapOptionalHex(IO, "File Flags", Info.FileFlags, 0);
  237. mapOptionalHex(IO, "File OS", Info.FileOS, 0);
  238. mapOptionalHex(IO, "File Type", Info.FileType, 0);
  239. mapOptionalHex(IO, "File Subtype", Info.FileSubtype, 0);
  240. mapOptionalHex(IO, "File Date High", Info.FileDateHigh, 0);
  241. mapOptionalHex(IO, "File Date Low", Info.FileDateLow, 0);
  242. }
  243. void yaml::MappingTraits<ModuleListStream::entry_type>::mapping(
  244. IO &IO, ModuleListStream::entry_type &M) {
  245. mapRequiredHex(IO, "Base of Image", M.Entry.BaseOfImage);
  246. mapRequiredHex(IO, "Size of Image", M.Entry.SizeOfImage);
  247. mapOptionalHex(IO, "Checksum", M.Entry.Checksum, 0);
  248. mapOptional(IO, "Time Date Stamp", M.Entry.TimeDateStamp, 0);
  249. IO.mapRequired("Module Name", M.Name);
  250. IO.mapOptional("Version Info", M.Entry.VersionInfo, VSFixedFileInfo());
  251. IO.mapRequired("CodeView Record", M.CvRecord);
  252. IO.mapOptional("Misc Record", M.MiscRecord, yaml::BinaryRef());
  253. mapOptionalHex(IO, "Reserved0", M.Entry.Reserved0, 0);
  254. mapOptionalHex(IO, "Reserved1", M.Entry.Reserved1, 0);
  255. }
  256. static void streamMapping(yaml::IO &IO, RawContentStream &Stream) {
  257. IO.mapOptional("Content", Stream.Content);
  258. IO.mapOptional("Size", Stream.Size, Stream.Content.binary_size());
  259. }
  260. static std::string streamValidate(RawContentStream &Stream) {
  261. if (Stream.Size.value < Stream.Content.binary_size())
  262. return "Stream size must be greater or equal to the content size";
  263. return "";
  264. }
  265. void yaml::MappingTraits<MemoryListStream::entry_type>::mapping(
  266. IO &IO, MemoryListStream::entry_type &Range) {
  267. MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
  268. IO, Range.Entry, Range.Content);
  269. }
  270. static void streamMapping(yaml::IO &IO, MemoryInfoListStream &Stream) {
  271. IO.mapRequired("Memory Ranges", Stream.Infos);
  272. }
  273. static void streamMapping(yaml::IO &IO, MemoryListStream &Stream) {
  274. IO.mapRequired("Memory Ranges", Stream.Entries);
  275. }
  276. static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) {
  277. IO.mapRequired("Modules", Stream.Entries);
  278. }
  279. static void streamMapping(yaml::IO &IO, SystemInfoStream &Stream) {
  280. SystemInfo &Info = Stream.Info;
  281. IO.mapRequired("Processor Arch", Info.ProcessorArch);
  282. mapOptional(IO, "Processor Level", Info.ProcessorLevel, 0);
  283. mapOptional(IO, "Processor Revision", Info.ProcessorRevision, 0);
  284. IO.mapOptional("Number of Processors", Info.NumberOfProcessors, 0);
  285. IO.mapOptional("Product type", Info.ProductType, 0);
  286. mapOptional(IO, "Major Version", Info.MajorVersion, 0);
  287. mapOptional(IO, "Minor Version", Info.MinorVersion, 0);
  288. mapOptional(IO, "Build Number", Info.BuildNumber, 0);
  289. IO.mapRequired("Platform ID", Info.PlatformId);
  290. IO.mapOptional("CSD Version", Stream.CSDVersion, "");
  291. mapOptionalHex(IO, "Suite Mask", Info.SuiteMask, 0);
  292. mapOptionalHex(IO, "Reserved", Info.Reserved, 0);
  293. switch (static_cast<ProcessorArchitecture>(Info.ProcessorArch)) {
  294. case ProcessorArchitecture::X86:
  295. case ProcessorArchitecture::AMD64:
  296. IO.mapOptional("CPU", Info.CPU.X86);
  297. break;
  298. case ProcessorArchitecture::ARM:
  299. case ProcessorArchitecture::ARM64:
  300. case ProcessorArchitecture::BP_ARM64:
  301. IO.mapOptional("CPU", Info.CPU.Arm);
  302. break;
  303. default:
  304. IO.mapOptional("CPU", Info.CPU.Other);
  305. break;
  306. }
  307. }
  308. static void streamMapping(yaml::IO &IO, TextContentStream &Stream) {
  309. IO.mapOptional("Text", Stream.Text);
  310. }
  311. void yaml::MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
  312. IO &IO, MemoryDescriptor &Memory, BinaryRef &Content) {
  313. mapRequiredHex(IO, "Start of Memory Range", Memory.StartOfMemoryRange);
  314. IO.mapRequired("Content", Content);
  315. }
  316. void yaml::MappingTraits<ThreadListStream::entry_type>::mapping(
  317. IO &IO, ThreadListStream::entry_type &T) {
  318. mapRequiredHex(IO, "Thread Id", T.Entry.ThreadId);
  319. mapOptionalHex(IO, "Suspend Count", T.Entry.SuspendCount, 0);
  320. mapOptionalHex(IO, "Priority Class", T.Entry.PriorityClass, 0);
  321. mapOptionalHex(IO, "Priority", T.Entry.Priority, 0);
  322. mapOptionalHex(IO, "Environment Block", T.Entry.EnvironmentBlock, 0);
  323. IO.mapRequired("Context", T.Context);
  324. IO.mapRequired("Stack", T.Entry.Stack, T.Stack);
  325. }
  326. static void streamMapping(yaml::IO &IO, ThreadListStream &Stream) {
  327. IO.mapRequired("Threads", Stream.Entries);
  328. }
  329. static void streamMapping(yaml::IO &IO, MinidumpYAML::ExceptionStream &Stream) {
  330. mapRequiredHex(IO, "Thread ID", Stream.MDExceptionStream.ThreadId);
  331. IO.mapRequired("Exception Record", Stream.MDExceptionStream.ExceptionRecord);
  332. IO.mapRequired("Thread Context", Stream.ThreadContext);
  333. }
  334. void yaml::MappingTraits<minidump::Exception>::mapping(
  335. yaml::IO &IO, minidump::Exception &Exception) {
  336. mapRequiredHex(IO, "Exception Code", Exception.ExceptionCode);
  337. mapOptionalHex(IO, "Exception Flags", Exception.ExceptionFlags, 0);
  338. mapOptionalHex(IO, "Exception Record", Exception.ExceptionRecord, 0);
  339. mapOptionalHex(IO, "Exception Address", Exception.ExceptionAddress, 0);
  340. mapOptional(IO, "Number of Parameters", Exception.NumberParameters, 0);
  341. for (size_t Index = 0; Index < Exception.MaxParameters; ++Index) {
  342. SmallString<16> Name("Parameter ");
  343. Twine(Index).toVector(Name);
  344. support::ulittle64_t &Field = Exception.ExceptionInformation[Index];
  345. if (Index < Exception.NumberParameters)
  346. mapRequiredHex(IO, Name.c_str(), Field);
  347. else
  348. mapOptionalHex(IO, Name.c_str(), Field, 0);
  349. }
  350. }
  351. void yaml::MappingTraits<std::unique_ptr<Stream>>::mapping(
  352. yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) {
  353. StreamType Type;
  354. if (IO.outputting())
  355. Type = S->Type;
  356. IO.mapRequired("Type", Type);
  357. if (!IO.outputting())
  358. S = MinidumpYAML::Stream::create(Type);
  359. switch (S->Kind) {
  360. case MinidumpYAML::Stream::StreamKind::Exception:
  361. streamMapping(IO, llvm::cast<MinidumpYAML::ExceptionStream>(*S));
  362. break;
  363. case MinidumpYAML::Stream::StreamKind::MemoryInfoList:
  364. streamMapping(IO, llvm::cast<MemoryInfoListStream>(*S));
  365. break;
  366. case MinidumpYAML::Stream::StreamKind::MemoryList:
  367. streamMapping(IO, llvm::cast<MemoryListStream>(*S));
  368. break;
  369. case MinidumpYAML::Stream::StreamKind::ModuleList:
  370. streamMapping(IO, llvm::cast<ModuleListStream>(*S));
  371. break;
  372. case MinidumpYAML::Stream::StreamKind::RawContent:
  373. streamMapping(IO, llvm::cast<RawContentStream>(*S));
  374. break;
  375. case MinidumpYAML::Stream::StreamKind::SystemInfo:
  376. streamMapping(IO, llvm::cast<SystemInfoStream>(*S));
  377. break;
  378. case MinidumpYAML::Stream::StreamKind::TextContent:
  379. streamMapping(IO, llvm::cast<TextContentStream>(*S));
  380. break;
  381. case MinidumpYAML::Stream::StreamKind::ThreadList:
  382. streamMapping(IO, llvm::cast<ThreadListStream>(*S));
  383. break;
  384. }
  385. }
  386. std::string yaml::MappingTraits<std::unique_ptr<Stream>>::validate(
  387. yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) {
  388. switch (S->Kind) {
  389. case MinidumpYAML::Stream::StreamKind::RawContent:
  390. return streamValidate(cast<RawContentStream>(*S));
  391. case MinidumpYAML::Stream::StreamKind::Exception:
  392. case MinidumpYAML::Stream::StreamKind::MemoryInfoList:
  393. case MinidumpYAML::Stream::StreamKind::MemoryList:
  394. case MinidumpYAML::Stream::StreamKind::ModuleList:
  395. case MinidumpYAML::Stream::StreamKind::SystemInfo:
  396. case MinidumpYAML::Stream::StreamKind::TextContent:
  397. case MinidumpYAML::Stream::StreamKind::ThreadList:
  398. return "";
  399. }
  400. llvm_unreachable("Fully covered switch above!");
  401. }
  402. void yaml::MappingTraits<Object>::mapping(IO &IO, Object &O) {
  403. IO.mapTag("!minidump", true);
  404. mapOptionalHex(IO, "Signature", O.Header.Signature, Header::MagicSignature);
  405. mapOptionalHex(IO, "Version", O.Header.Version, Header::MagicVersion);
  406. mapOptionalHex(IO, "Flags", O.Header.Flags, 0);
  407. IO.mapRequired("Streams", O.Streams);
  408. }
  409. Expected<std::unique_ptr<Stream>>
  410. Stream::create(const Directory &StreamDesc, const object::MinidumpFile &File) {
  411. StreamKind Kind = getKind(StreamDesc.Type);
  412. switch (Kind) {
  413. case StreamKind::Exception: {
  414. Expected<const minidump::ExceptionStream &> ExpectedExceptionStream =
  415. File.getExceptionStream();
  416. if (!ExpectedExceptionStream)
  417. return ExpectedExceptionStream.takeError();
  418. Expected<ArrayRef<uint8_t>> ExpectedThreadContext =
  419. File.getRawData(ExpectedExceptionStream->ThreadContext);
  420. if (!ExpectedThreadContext)
  421. return ExpectedThreadContext.takeError();
  422. return std::make_unique<ExceptionStream>(*ExpectedExceptionStream,
  423. *ExpectedThreadContext);
  424. }
  425. case StreamKind::MemoryInfoList: {
  426. if (auto ExpectedList = File.getMemoryInfoList())
  427. return std::make_unique<MemoryInfoListStream>(*ExpectedList);
  428. else
  429. return ExpectedList.takeError();
  430. }
  431. case StreamKind::MemoryList: {
  432. auto ExpectedList = File.getMemoryList();
  433. if (!ExpectedList)
  434. return ExpectedList.takeError();
  435. std::vector<MemoryListStream::entry_type> Ranges;
  436. for (const MemoryDescriptor &MD : *ExpectedList) {
  437. auto ExpectedContent = File.getRawData(MD.Memory);
  438. if (!ExpectedContent)
  439. return ExpectedContent.takeError();
  440. Ranges.push_back({MD, *ExpectedContent});
  441. }
  442. return std::make_unique<MemoryListStream>(std::move(Ranges));
  443. }
  444. case StreamKind::ModuleList: {
  445. auto ExpectedList = File.getModuleList();
  446. if (!ExpectedList)
  447. return ExpectedList.takeError();
  448. std::vector<ModuleListStream::entry_type> Modules;
  449. for (const Module &M : *ExpectedList) {
  450. auto ExpectedName = File.getString(M.ModuleNameRVA);
  451. if (!ExpectedName)
  452. return ExpectedName.takeError();
  453. auto ExpectedCv = File.getRawData(M.CvRecord);
  454. if (!ExpectedCv)
  455. return ExpectedCv.takeError();
  456. auto ExpectedMisc = File.getRawData(M.MiscRecord);
  457. if (!ExpectedMisc)
  458. return ExpectedMisc.takeError();
  459. Modules.push_back(
  460. {M, std::move(*ExpectedName), *ExpectedCv, *ExpectedMisc});
  461. }
  462. return std::make_unique<ModuleListStream>(std::move(Modules));
  463. }
  464. case StreamKind::RawContent:
  465. return std::make_unique<RawContentStream>(StreamDesc.Type,
  466. File.getRawStream(StreamDesc));
  467. case StreamKind::SystemInfo: {
  468. auto ExpectedInfo = File.getSystemInfo();
  469. if (!ExpectedInfo)
  470. return ExpectedInfo.takeError();
  471. auto ExpectedCSDVersion = File.getString(ExpectedInfo->CSDVersionRVA);
  472. if (!ExpectedCSDVersion)
  473. return ExpectedInfo.takeError();
  474. return std::make_unique<SystemInfoStream>(*ExpectedInfo,
  475. std::move(*ExpectedCSDVersion));
  476. }
  477. case StreamKind::TextContent:
  478. return std::make_unique<TextContentStream>(
  479. StreamDesc.Type, toStringRef(File.getRawStream(StreamDesc)));
  480. case StreamKind::ThreadList: {
  481. auto ExpectedList = File.getThreadList();
  482. if (!ExpectedList)
  483. return ExpectedList.takeError();
  484. std::vector<ThreadListStream::entry_type> Threads;
  485. for (const Thread &T : *ExpectedList) {
  486. auto ExpectedStack = File.getRawData(T.Stack.Memory);
  487. if (!ExpectedStack)
  488. return ExpectedStack.takeError();
  489. auto ExpectedContext = File.getRawData(T.Context);
  490. if (!ExpectedContext)
  491. return ExpectedContext.takeError();
  492. Threads.push_back({T, *ExpectedStack, *ExpectedContext});
  493. }
  494. return std::make_unique<ThreadListStream>(std::move(Threads));
  495. }
  496. }
  497. llvm_unreachable("Unhandled stream kind!");
  498. }
  499. Expected<Object> Object::create(const object::MinidumpFile &File) {
  500. std::vector<std::unique_ptr<Stream>> Streams;
  501. Streams.reserve(File.streams().size());
  502. for (const Directory &StreamDesc : File.streams()) {
  503. auto ExpectedStream = Stream::create(StreamDesc, File);
  504. if (!ExpectedStream)
  505. return ExpectedStream.takeError();
  506. Streams.push_back(std::move(*ExpectedStream));
  507. }
  508. return Object(File.header(), std::move(Streams));
  509. }