1 //===- MinidumpYAML.cpp - Minidump YAMLIO implementation ------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ObjectYAML/MinidumpYAML.h"
12 using namespace llvm::MinidumpYAML
;
13 using namespace llvm::minidump
;
15 /// Perform an optional yaml-mapping of an endian-aware type EndianType. The
16 /// only purpose of this function is to avoid casting the Default value to the
18 template <typename EndianType
>
19 static inline void mapOptional(yaml::IO
&IO
, const char *Key
, EndianType
&Val
,
20 typename
EndianType::value_type Default
) {
21 IO
.mapOptional(Key
, Val
, EndianType(Default
));
24 /// Yaml-map an endian-aware type EndianType as some other type MapType.
25 template <typename MapType
, typename EndianType
>
26 static inline void mapRequiredAs(yaml::IO
&IO
, const char *Key
,
28 MapType Mapped
= static_cast<typename
EndianType::value_type
>(Val
);
29 IO
.mapRequired(Key
, Mapped
);
30 Val
= static_cast<typename
EndianType::value_type
>(Mapped
);
33 /// Perform an optional yaml-mapping of an endian-aware type EndianType as some
34 /// other type MapType.
35 template <typename MapType
, typename EndianType
>
36 static inline void mapOptionalAs(yaml::IO
&IO
, const char *Key
, EndianType
&Val
,
38 MapType Mapped
= static_cast<typename
EndianType::value_type
>(Val
);
39 IO
.mapOptional(Key
, Mapped
, Default
);
40 Val
= static_cast<typename
EndianType::value_type
>(Mapped
);
44 /// Return the appropriate yaml Hex type for a given endian-aware type.
45 template <typename EndianType
> struct HexType
;
46 template <> struct HexType
<support::ulittle16_t
> { using type
= yaml::Hex16
; };
47 template <> struct HexType
<support::ulittle32_t
> { using type
= yaml::Hex32
; };
48 template <> struct HexType
<support::ulittle64_t
> { using type
= yaml::Hex64
; };
51 /// Yaml-map an endian-aware type as an appropriately-sized hex value.
52 template <typename EndianType
>
53 static inline void mapRequiredHex(yaml::IO
&IO
, const char *Key
,
55 mapRequiredAs
<typename HexType
<EndianType
>::type
>(IO
, Key
, Val
);
58 /// Perform an optional yaml-mapping of an endian-aware type as an
59 /// appropriately-sized hex value.
60 template <typename EndianType
>
61 static inline void mapOptionalHex(yaml::IO
&IO
, const char *Key
,
63 typename
EndianType::value_type Default
) {
64 mapOptionalAs
<typename HexType
<EndianType
>::type
>(IO
, Key
, Val
, Default
);
67 Stream::~Stream() = default;
69 Stream::StreamKind
Stream::getKind(StreamType Type
) {
71 case StreamType::Exception
:
72 return StreamKind::Exception
;
73 case StreamType::MemoryInfoList
:
74 return StreamKind::MemoryInfoList
;
75 case StreamType::MemoryList
:
76 return StreamKind::MemoryList
;
77 case StreamType::Memory64List
:
78 return StreamKind::Memory64List
;
79 case StreamType::ModuleList
:
80 return StreamKind::ModuleList
;
81 case StreamType::SystemInfo
:
82 return StreamKind::SystemInfo
;
83 case StreamType::LinuxCPUInfo
:
84 case StreamType::LinuxProcStatus
:
85 case StreamType::LinuxLSBRelease
:
86 case StreamType::LinuxCMDLine
:
87 case StreamType::LinuxMaps
:
88 case StreamType::LinuxProcStat
:
89 case StreamType::LinuxProcUptime
:
90 return StreamKind::TextContent
;
91 case StreamType::ThreadList
:
92 return StreamKind::ThreadList
;
94 return StreamKind::RawContent
;
98 std::unique_ptr
<Stream
> Stream::create(StreamType Type
) {
99 StreamKind Kind
= getKind(Type
);
101 case StreamKind::Exception
:
102 return std::make_unique
<ExceptionStream
>();
103 case StreamKind::MemoryInfoList
:
104 return std::make_unique
<MemoryInfoListStream
>();
105 case StreamKind::MemoryList
:
106 return std::make_unique
<MemoryListStream
>();
107 case StreamKind::Memory64List
:
108 return std::make_unique
<Memory64ListStream
>();
109 case StreamKind::ModuleList
:
110 return std::make_unique
<ModuleListStream
>();
111 case StreamKind::RawContent
:
112 return std::make_unique
<RawContentStream
>(Type
);
113 case StreamKind::SystemInfo
:
114 return std::make_unique
<SystemInfoStream
>();
115 case StreamKind::TextContent
:
116 return std::make_unique
<TextContentStream
>(Type
);
117 case StreamKind::ThreadList
:
118 return std::make_unique
<ThreadListStream
>();
120 llvm_unreachable("Unhandled stream kind!");
123 void yaml::ScalarBitSetTraits
<MemoryProtection
>::bitset(
124 IO
&IO
, MemoryProtection
&Protect
) {
125 #define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME) \
126 IO.bitSetCase(Protect, #NATIVENAME, MemoryProtection::NAME);
127 #include "llvm/BinaryFormat/MinidumpConstants.def"
130 void yaml::ScalarBitSetTraits
<MemoryState
>::bitset(IO
&IO
, MemoryState
&State
) {
131 #define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME) \
132 IO.bitSetCase(State, #NATIVENAME, MemoryState::NAME);
133 #include "llvm/BinaryFormat/MinidumpConstants.def"
136 void yaml::ScalarBitSetTraits
<MemoryType
>::bitset(IO
&IO
, MemoryType
&Type
) {
137 #define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME) \
138 IO.bitSetCase(Type, #NATIVENAME, MemoryType::NAME);
139 #include "llvm/BinaryFormat/MinidumpConstants.def"
142 void yaml::ScalarEnumerationTraits
<ProcessorArchitecture
>::enumeration(
143 IO
&IO
, ProcessorArchitecture
&Arch
) {
144 #define HANDLE_MDMP_ARCH(CODE, NAME) \
145 IO.enumCase(Arch, #NAME, ProcessorArchitecture::NAME);
146 #include "llvm/BinaryFormat/MinidumpConstants.def"
147 IO
.enumFallback
<Hex16
>(Arch
);
150 void yaml::ScalarEnumerationTraits
<OSPlatform
>::enumeration(IO
&IO
,
152 #define HANDLE_MDMP_PLATFORM(CODE, NAME) \
153 IO.enumCase(Plat, #NAME, OSPlatform::NAME);
154 #include "llvm/BinaryFormat/MinidumpConstants.def"
155 IO
.enumFallback
<Hex32
>(Plat
);
158 void yaml::ScalarEnumerationTraits
<StreamType
>::enumeration(IO
&IO
,
160 #define HANDLE_MDMP_STREAM_TYPE(CODE, NAME) \
161 IO.enumCase(Type, #NAME, StreamType::NAME);
162 #include "llvm/BinaryFormat/MinidumpConstants.def"
163 IO
.enumFallback
<Hex32
>(Type
);
166 void yaml::MappingTraits
<CPUInfo::ArmInfo
>::mapping(IO
&IO
,
167 CPUInfo::ArmInfo
&Info
) {
168 mapRequiredHex(IO
, "CPUID", Info
.CPUID
);
169 mapOptionalHex(IO
, "ELF hwcaps", Info
.ElfHWCaps
, 0);
173 template <std::size_t N
> struct FixedSizeHex
{
174 FixedSizeHex(uint8_t (&Storage
)[N
]) : Storage(Storage
) {}
176 uint8_t (&Storage
)[N
];
182 template <std::size_t N
> struct ScalarTraits
<FixedSizeHex
<N
>> {
183 static void output(const FixedSizeHex
<N
> &Fixed
, void *, raw_ostream
&OS
) {
184 OS
<< toHex(ArrayRef(Fixed
.Storage
));
187 static StringRef
input(StringRef Scalar
, void *, FixedSizeHex
<N
> &Fixed
) {
188 if (!all_of(Scalar
, isHexDigit
))
189 return "Invalid hex digit in input";
190 if (Scalar
.size() < 2 * N
)
191 return "String too short";
192 if (Scalar
.size() > 2 * N
)
193 return "String too long";
194 copy(fromHex(Scalar
), Fixed
.Storage
);
198 static QuotingType
mustQuote(StringRef S
) { return QuotingType::None
; }
202 void yaml::MappingTraits
<CPUInfo::OtherInfo
>::mapping(
203 IO
&IO
, CPUInfo::OtherInfo
&Info
) {
204 FixedSizeHex
<sizeof(Info
.ProcessorFeatures
)> Features(Info
.ProcessorFeatures
);
205 IO
.mapRequired("Features", Features
);
209 /// A type which only accepts strings of a fixed size for yaml conversion.
210 template <std::size_t N
> struct FixedSizeString
{
211 FixedSizeString(char (&Storage
)[N
]) : Storage(Storage
) {}
219 template <std::size_t N
> struct ScalarTraits
<FixedSizeString
<N
>> {
220 static void output(const FixedSizeString
<N
> &Fixed
, void *, raw_ostream
&OS
) {
221 OS
<< StringRef(Fixed
.Storage
, N
);
224 static StringRef
input(StringRef Scalar
, void *, FixedSizeString
<N
> &Fixed
) {
225 if (Scalar
.size() < N
)
226 return "String too short";
227 if (Scalar
.size() > N
)
228 return "String too long";
229 copy(Scalar
, Fixed
.Storage
);
233 static QuotingType
mustQuote(StringRef S
) { return needsQuotes(S
); }
238 void yaml::MappingTraits
<CPUInfo::X86Info
>::mapping(IO
&IO
,
239 CPUInfo::X86Info
&Info
) {
240 FixedSizeString
<sizeof(Info
.VendorID
)> VendorID(Info
.VendorID
);
241 IO
.mapRequired("Vendor ID", VendorID
);
243 mapRequiredHex(IO
, "Version Info", Info
.VersionInfo
);
244 mapRequiredHex(IO
, "Feature Info", Info
.FeatureInfo
);
245 mapOptionalHex(IO
, "AMD Extended Features", Info
.AMDExtendedFeatures
, 0);
248 void yaml::MappingTraits
<MemoryInfo
>::mapping(IO
&IO
, MemoryInfo
&Info
) {
249 mapRequiredHex(IO
, "Base Address", Info
.BaseAddress
);
250 mapOptionalHex(IO
, "Allocation Base", Info
.AllocationBase
, Info
.BaseAddress
);
251 mapRequiredAs
<MemoryProtection
>(IO
, "Allocation Protect",
252 Info
.AllocationProtect
);
253 mapOptionalHex(IO
, "Reserved0", Info
.Reserved0
, 0);
254 mapRequiredHex(IO
, "Region Size", Info
.RegionSize
);
255 mapRequiredAs
<MemoryState
>(IO
, "State", Info
.State
);
256 mapOptionalAs
<MemoryProtection
>(IO
, "Protect", Info
.Protect
,
257 Info
.AllocationProtect
);
258 mapRequiredAs
<MemoryType
>(IO
, "Type", Info
.Type
);
259 mapOptionalHex(IO
, "Reserved1", Info
.Reserved1
, 0);
262 void yaml::MappingTraits
<Memory64ListStream::entry_type
>::mapping(
263 IO
&IO
, Memory64ListStream::entry_type
&Mem
) {
264 MappingContextTraits
<MemoryDescriptor_64
, yaml::BinaryRef
>::mapping(
265 IO
, Mem
.Entry
, Mem
.Content
);
268 void yaml::MappingTraits
<VSFixedFileInfo
>::mapping(IO
&IO
,
269 VSFixedFileInfo
&Info
) {
270 mapOptionalHex(IO
, "Signature", Info
.Signature
, 0);
271 mapOptionalHex(IO
, "Struct Version", Info
.StructVersion
, 0);
272 mapOptionalHex(IO
, "File Version High", Info
.FileVersionHigh
, 0);
273 mapOptionalHex(IO
, "File Version Low", Info
.FileVersionLow
, 0);
274 mapOptionalHex(IO
, "Product Version High", Info
.ProductVersionHigh
, 0);
275 mapOptionalHex(IO
, "Product Version Low", Info
.ProductVersionLow
, 0);
276 mapOptionalHex(IO
, "File Flags Mask", Info
.FileFlagsMask
, 0);
277 mapOptionalHex(IO
, "File Flags", Info
.FileFlags
, 0);
278 mapOptionalHex(IO
, "File OS", Info
.FileOS
, 0);
279 mapOptionalHex(IO
, "File Type", Info
.FileType
, 0);
280 mapOptionalHex(IO
, "File Subtype", Info
.FileSubtype
, 0);
281 mapOptionalHex(IO
, "File Date High", Info
.FileDateHigh
, 0);
282 mapOptionalHex(IO
, "File Date Low", Info
.FileDateLow
, 0);
285 void yaml::MappingTraits
<ModuleListStream::entry_type
>::mapping(
286 IO
&IO
, ModuleListStream::entry_type
&M
) {
287 mapRequiredHex(IO
, "Base of Image", M
.Entry
.BaseOfImage
);
288 mapRequiredHex(IO
, "Size of Image", M
.Entry
.SizeOfImage
);
289 mapOptionalHex(IO
, "Checksum", M
.Entry
.Checksum
, 0);
290 mapOptional(IO
, "Time Date Stamp", M
.Entry
.TimeDateStamp
, 0);
291 IO
.mapRequired("Module Name", M
.Name
);
292 IO
.mapOptional("Version Info", M
.Entry
.VersionInfo
, VSFixedFileInfo());
293 IO
.mapRequired("CodeView Record", M
.CvRecord
);
294 IO
.mapOptional("Misc Record", M
.MiscRecord
, yaml::BinaryRef());
295 mapOptionalHex(IO
, "Reserved0", M
.Entry
.Reserved0
, 0);
296 mapOptionalHex(IO
, "Reserved1", M
.Entry
.Reserved1
, 0);
299 static void streamMapping(yaml::IO
&IO
, RawContentStream
&Stream
) {
300 IO
.mapOptional("Content", Stream
.Content
);
301 IO
.mapOptional("Size", Stream
.Size
, Stream
.Content
.binary_size());
304 static std::string
streamValidate(RawContentStream
&Stream
) {
305 if (Stream
.Size
.value
< Stream
.Content
.binary_size())
306 return "Stream size must be greater or equal to the content size";
310 void yaml::MappingTraits
<MemoryListStream::entry_type
>::mapping(
311 IO
&IO
, MemoryListStream::entry_type
&Range
) {
312 MappingContextTraits
<MemoryDescriptor
, yaml::BinaryRef
>::mapping(
313 IO
, Range
.Entry
, Range
.Content
);
316 static void streamMapping(yaml::IO
&IO
, MemoryInfoListStream
&Stream
) {
317 IO
.mapRequired("Memory Ranges", Stream
.Infos
);
320 static void streamMapping(yaml::IO
&IO
, MemoryListStream
&Stream
) {
321 IO
.mapRequired("Memory Ranges", Stream
.Entries
);
324 static void streamMapping(yaml::IO
&IO
, Memory64ListStream
&Stream
) {
325 IO
.mapRequired("Memory Ranges", Stream
.Entries
);
328 static std::string
streamValidate(Memory64ListStream
&Stream
) {
329 for (auto &Entry
: Stream
.Entries
) {
330 if (Entry
.Entry
.DataSize
< Entry
.Content
.binary_size())
331 return "Memory region size must be greater or equal to the content size";
336 static void streamMapping(yaml::IO
&IO
, ModuleListStream
&Stream
) {
337 IO
.mapRequired("Modules", Stream
.Entries
);
340 static void streamMapping(yaml::IO
&IO
, SystemInfoStream
&Stream
) {
341 SystemInfo
&Info
= Stream
.Info
;
342 IO
.mapRequired("Processor Arch", Info
.ProcessorArch
);
343 mapOptional(IO
, "Processor Level", Info
.ProcessorLevel
, 0);
344 mapOptional(IO
, "Processor Revision", Info
.ProcessorRevision
, 0);
345 IO
.mapOptional("Number of Processors", Info
.NumberOfProcessors
, 0);
346 IO
.mapOptional("Product type", Info
.ProductType
, 0);
347 mapOptional(IO
, "Major Version", Info
.MajorVersion
, 0);
348 mapOptional(IO
, "Minor Version", Info
.MinorVersion
, 0);
349 mapOptional(IO
, "Build Number", Info
.BuildNumber
, 0);
350 IO
.mapRequired("Platform ID", Info
.PlatformId
);
351 IO
.mapOptional("CSD Version", Stream
.CSDVersion
, "");
352 mapOptionalHex(IO
, "Suite Mask", Info
.SuiteMask
, 0);
353 mapOptionalHex(IO
, "Reserved", Info
.Reserved
, 0);
354 switch (static_cast<ProcessorArchitecture
>(Info
.ProcessorArch
)) {
355 case ProcessorArchitecture::X86
:
356 case ProcessorArchitecture::AMD64
:
357 IO
.mapOptional("CPU", Info
.CPU
.X86
);
359 case ProcessorArchitecture::ARM
:
360 case ProcessorArchitecture::ARM64
:
361 case ProcessorArchitecture::BP_ARM64
:
362 IO
.mapOptional("CPU", Info
.CPU
.Arm
);
365 IO
.mapOptional("CPU", Info
.CPU
.Other
);
370 static void streamMapping(yaml::IO
&IO
, TextContentStream
&Stream
) {
371 IO
.mapOptional("Text", Stream
.Text
);
374 void yaml::MappingContextTraits
<MemoryDescriptor
, yaml::BinaryRef
>::mapping(
375 IO
&IO
, MemoryDescriptor
&Memory
, BinaryRef
&Content
) {
376 mapRequiredHex(IO
, "Start of Memory Range", Memory
.StartOfMemoryRange
);
377 IO
.mapRequired("Content", Content
);
380 void yaml::MappingContextTraits
<MemoryDescriptor_64
, yaml::BinaryRef
>::mapping(
381 IO
&IO
, MemoryDescriptor_64
&Memory
, BinaryRef
&Content
) {
382 mapRequiredHex(IO
, "Start of Memory Range", Memory
.StartOfMemoryRange
);
383 IO
.mapRequired("Content", Content
);
384 mapOptional(IO
, "Data Size", Memory
.DataSize
, Content
.binary_size());
387 void yaml::MappingTraits
<ThreadListStream::entry_type
>::mapping(
388 IO
&IO
, ThreadListStream::entry_type
&T
) {
389 mapRequiredHex(IO
, "Thread Id", T
.Entry
.ThreadId
);
390 mapOptionalHex(IO
, "Suspend Count", T
.Entry
.SuspendCount
, 0);
391 mapOptionalHex(IO
, "Priority Class", T
.Entry
.PriorityClass
, 0);
392 mapOptionalHex(IO
, "Priority", T
.Entry
.Priority
, 0);
393 mapOptionalHex(IO
, "Environment Block", T
.Entry
.EnvironmentBlock
, 0);
394 IO
.mapRequired("Context", T
.Context
);
395 IO
.mapRequired("Stack", T
.Entry
.Stack
, T
.Stack
);
398 static void streamMapping(yaml::IO
&IO
, ThreadListStream
&Stream
) {
399 IO
.mapRequired("Threads", Stream
.Entries
);
402 static void streamMapping(yaml::IO
&IO
, MinidumpYAML::ExceptionStream
&Stream
) {
403 mapRequiredHex(IO
, "Thread ID", Stream
.MDExceptionStream
.ThreadId
);
404 IO
.mapRequired("Exception Record", Stream
.MDExceptionStream
.ExceptionRecord
);
405 IO
.mapRequired("Thread Context", Stream
.ThreadContext
);
408 void yaml::MappingTraits
<minidump::Exception
>::mapping(
409 yaml::IO
&IO
, minidump::Exception
&Exception
) {
410 mapRequiredHex(IO
, "Exception Code", Exception
.ExceptionCode
);
411 mapOptionalHex(IO
, "Exception Flags", Exception
.ExceptionFlags
, 0);
412 mapOptionalHex(IO
, "Exception Record", Exception
.ExceptionRecord
, 0);
413 mapOptionalHex(IO
, "Exception Address", Exception
.ExceptionAddress
, 0);
414 mapOptional(IO
, "Number of Parameters", Exception
.NumberParameters
, 0);
416 for (size_t Index
= 0; Index
< Exception
.MaxParameters
; ++Index
) {
417 SmallString
<16> Name("Parameter ");
418 Twine(Index
).toVector(Name
);
419 support::ulittle64_t
&Field
= Exception
.ExceptionInformation
[Index
];
421 if (Index
< Exception
.NumberParameters
)
422 mapRequiredHex(IO
, Name
.c_str(), Field
);
424 mapOptionalHex(IO
, Name
.c_str(), Field
, 0);
428 void yaml::MappingTraits
<std::unique_ptr
<Stream
>>::mapping(
429 yaml::IO
&IO
, std::unique_ptr
<MinidumpYAML::Stream
> &S
) {
433 IO
.mapRequired("Type", Type
);
435 if (!IO
.outputting())
436 S
= MinidumpYAML::Stream::create(Type
);
438 case MinidumpYAML::Stream::StreamKind::Exception
:
439 streamMapping(IO
, llvm::cast
<MinidumpYAML::ExceptionStream
>(*S
));
441 case MinidumpYAML::Stream::StreamKind::MemoryInfoList
:
442 streamMapping(IO
, llvm::cast
<MemoryInfoListStream
>(*S
));
444 case MinidumpYAML::Stream::StreamKind::MemoryList
:
445 streamMapping(IO
, llvm::cast
<MemoryListStream
>(*S
));
447 case MinidumpYAML::Stream::StreamKind::Memory64List
:
448 streamMapping(IO
, llvm::cast
<Memory64ListStream
>(*S
));
450 case MinidumpYAML::Stream::StreamKind::ModuleList
:
451 streamMapping(IO
, llvm::cast
<ModuleListStream
>(*S
));
453 case MinidumpYAML::Stream::StreamKind::RawContent
:
454 streamMapping(IO
, llvm::cast
<RawContentStream
>(*S
));
456 case MinidumpYAML::Stream::StreamKind::SystemInfo
:
457 streamMapping(IO
, llvm::cast
<SystemInfoStream
>(*S
));
459 case MinidumpYAML::Stream::StreamKind::TextContent
:
460 streamMapping(IO
, llvm::cast
<TextContentStream
>(*S
));
462 case MinidumpYAML::Stream::StreamKind::ThreadList
:
463 streamMapping(IO
, llvm::cast
<ThreadListStream
>(*S
));
468 std::string
yaml::MappingTraits
<std::unique_ptr
<Stream
>>::validate(
469 yaml::IO
&IO
, std::unique_ptr
<MinidumpYAML::Stream
> &S
) {
471 case MinidumpYAML::Stream::StreamKind::RawContent
:
472 return streamValidate(cast
<RawContentStream
>(*S
));
473 case MinidumpYAML::Stream::StreamKind::Memory64List
:
474 return streamValidate(cast
<Memory64ListStream
>(*S
));
475 case MinidumpYAML::Stream::StreamKind::Exception
:
476 case MinidumpYAML::Stream::StreamKind::MemoryInfoList
:
477 case MinidumpYAML::Stream::StreamKind::MemoryList
:
478 case MinidumpYAML::Stream::StreamKind::ModuleList
:
479 case MinidumpYAML::Stream::StreamKind::SystemInfo
:
480 case MinidumpYAML::Stream::StreamKind::TextContent
:
481 case MinidumpYAML::Stream::StreamKind::ThreadList
:
484 llvm_unreachable("Fully covered switch above!");
487 void yaml::MappingTraits
<Object
>::mapping(IO
&IO
, Object
&O
) {
488 IO
.mapTag("!minidump", true);
489 mapOptionalHex(IO
, "Signature", O
.Header
.Signature
, Header::MagicSignature
);
490 mapOptionalHex(IO
, "Version", O
.Header
.Version
, Header::MagicVersion
);
491 mapOptionalHex(IO
, "Flags", O
.Header
.Flags
, 0);
492 IO
.mapRequired("Streams", O
.Streams
);
495 Expected
<std::unique_ptr
<Stream
>>
496 Stream::create(const Directory
&StreamDesc
, const object::MinidumpFile
&File
) {
497 StreamKind Kind
= getKind(StreamDesc
.Type
);
499 case StreamKind::Exception
: {
500 Expected
<const minidump::ExceptionStream
&> ExpectedExceptionStream
=
501 File
.getExceptionStream(StreamDesc
);
502 if (!ExpectedExceptionStream
)
503 return ExpectedExceptionStream
.takeError();
504 Expected
<ArrayRef
<uint8_t>> ExpectedThreadContext
=
505 File
.getRawData(ExpectedExceptionStream
->ThreadContext
);
506 if (!ExpectedThreadContext
)
507 return ExpectedThreadContext
.takeError();
508 return std::make_unique
<ExceptionStream
>(*ExpectedExceptionStream
,
509 *ExpectedThreadContext
);
511 case StreamKind::MemoryInfoList
: {
512 if (auto ExpectedList
= File
.getMemoryInfoList())
513 return std::make_unique
<MemoryInfoListStream
>(*ExpectedList
);
515 return ExpectedList
.takeError();
517 case StreamKind::MemoryList
: {
518 auto ExpectedList
= File
.getMemoryList();
520 return ExpectedList
.takeError();
521 std::vector
<MemoryListStream::entry_type
> Ranges
;
522 for (const MemoryDescriptor
&MD
: *ExpectedList
) {
523 auto ExpectedContent
= File
.getRawData(MD
.Memory
);
524 if (!ExpectedContent
)
525 return ExpectedContent
.takeError();
526 Ranges
.push_back({MD
, *ExpectedContent
});
528 return std::make_unique
<MemoryListStream
>(std::move(Ranges
));
530 case StreamKind::Memory64List
: {
531 Error Err
= Error::success();
532 auto Memory64List
= File
.getMemory64List(Err
);
533 std::vector
<Memory64ListStream::entry_type
> Ranges
;
534 for (const auto &Pair
: Memory64List
) {
535 Ranges
.push_back({Pair
.first
, Pair
.second
});
540 return std::make_unique
<Memory64ListStream
>(std::move(Ranges
));
542 case StreamKind::ModuleList
: {
543 auto ExpectedList
= File
.getModuleList();
545 return ExpectedList
.takeError();
546 std::vector
<ModuleListStream::entry_type
> Modules
;
547 for (const Module
&M
: *ExpectedList
) {
548 auto ExpectedName
= File
.getString(M
.ModuleNameRVA
);
550 return ExpectedName
.takeError();
551 auto ExpectedCv
= File
.getRawData(M
.CvRecord
);
553 return ExpectedCv
.takeError();
554 auto ExpectedMisc
= File
.getRawData(M
.MiscRecord
);
556 return ExpectedMisc
.takeError();
558 {M
, std::move(*ExpectedName
), *ExpectedCv
, *ExpectedMisc
});
560 return std::make_unique
<ModuleListStream
>(std::move(Modules
));
562 case StreamKind::RawContent
:
563 return std::make_unique
<RawContentStream
>(StreamDesc
.Type
,
564 File
.getRawStream(StreamDesc
));
565 case StreamKind::SystemInfo
: {
566 auto ExpectedInfo
= File
.getSystemInfo();
568 return ExpectedInfo
.takeError();
569 auto ExpectedCSDVersion
= File
.getString(ExpectedInfo
->CSDVersionRVA
);
570 if (!ExpectedCSDVersion
)
571 return ExpectedInfo
.takeError();
572 return std::make_unique
<SystemInfoStream
>(*ExpectedInfo
,
573 std::move(*ExpectedCSDVersion
));
575 case StreamKind::TextContent
:
576 return std::make_unique
<TextContentStream
>(
577 StreamDesc
.Type
, toStringRef(File
.getRawStream(StreamDesc
)));
578 case StreamKind::ThreadList
: {
579 auto ExpectedList
= File
.getThreadList();
581 return ExpectedList
.takeError();
582 std::vector
<ThreadListStream::entry_type
> Threads
;
583 for (const Thread
&T
: *ExpectedList
) {
584 auto ExpectedStack
= File
.getRawData(T
.Stack
.Memory
);
586 return ExpectedStack
.takeError();
587 auto ExpectedContext
= File
.getRawData(T
.Context
);
588 if (!ExpectedContext
)
589 return ExpectedContext
.takeError();
590 Threads
.push_back({T
, *ExpectedStack
, *ExpectedContext
});
592 return std::make_unique
<ThreadListStream
>(std::move(Threads
));
595 llvm_unreachable("Unhandled stream kind!");
598 Expected
<Object
> Object::create(const object::MinidumpFile
&File
) {
599 std::vector
<std::unique_ptr
<Stream
>> Streams
;
600 Streams
.reserve(File
.streams().size());
601 for (const Directory
&StreamDesc
: File
.streams()) {
602 auto ExpectedStream
= Stream::create(StreamDesc
, File
);
604 return ExpectedStream
.takeError();
605 Streams
.push_back(std::move(*ExpectedStream
));
607 return Object(File
.header(), std::move(Streams
));