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"
10 #include "llvm/Support/Allocator.h"
13 using namespace llvm::MinidumpYAML
;
14 using namespace llvm::minidump
;
16 /// Perform an optional yaml-mapping of an endian-aware type EndianType. The
17 /// only purpose of this function is to avoid casting the Default value to the
19 template <typename EndianType
>
20 static inline void mapOptional(yaml::IO
&IO
, const char *Key
, EndianType
&Val
,
21 typename
EndianType::value_type Default
) {
22 IO
.mapOptional(Key
, Val
, EndianType(Default
));
25 /// Yaml-map an endian-aware type EndianType as some other type MapType.
26 template <typename MapType
, typename EndianType
>
27 static inline void mapRequiredAs(yaml::IO
&IO
, const char *Key
,
29 MapType Mapped
= static_cast<typename
EndianType::value_type
>(Val
);
30 IO
.mapRequired(Key
, Mapped
);
31 Val
= static_cast<typename
EndianType::value_type
>(Mapped
);
34 /// Perform an optional yaml-mapping of an endian-aware type EndianType as some
35 /// other type MapType.
36 template <typename MapType
, typename EndianType
>
37 static inline void mapOptionalAs(yaml::IO
&IO
, const char *Key
, EndianType
&Val
,
39 MapType Mapped
= static_cast<typename
EndianType::value_type
>(Val
);
40 IO
.mapOptional(Key
, Mapped
, Default
);
41 Val
= static_cast<typename
EndianType::value_type
>(Mapped
);
45 /// Return the appropriate yaml Hex type for a given endian-aware type.
46 template <typename EndianType
> struct HexType
;
47 template <> struct HexType
<support::ulittle16_t
> { using type
= yaml::Hex16
; };
48 template <> struct HexType
<support::ulittle32_t
> { using type
= yaml::Hex32
; };
49 template <> struct HexType
<support::ulittle64_t
> { using type
= yaml::Hex64
; };
52 /// Yaml-map an endian-aware type as an appropriately-sized hex value.
53 template <typename EndianType
>
54 static inline void mapRequiredHex(yaml::IO
&IO
, const char *Key
,
56 mapRequiredAs
<typename HexType
<EndianType
>::type
>(IO
, Key
, Val
);
59 /// Perform an optional yaml-mapping of an endian-aware type as an
60 /// appropriately-sized hex value.
61 template <typename EndianType
>
62 static inline void mapOptionalHex(yaml::IO
&IO
, const char *Key
,
64 typename
EndianType::value_type Default
) {
65 mapOptionalAs
<typename HexType
<EndianType
>::type
>(IO
, Key
, Val
, Default
);
68 Stream::~Stream() = default;
70 Stream::StreamKind
Stream::getKind(StreamType Type
) {
72 case StreamType::Exception
:
73 return StreamKind::Exception
;
74 case StreamType::MemoryInfoList
:
75 return StreamKind::MemoryInfoList
;
76 case StreamType::MemoryList
:
77 return StreamKind::MemoryList
;
78 case StreamType::ModuleList
:
79 return StreamKind::ModuleList
;
80 case StreamType::SystemInfo
:
81 return StreamKind::SystemInfo
;
82 case StreamType::LinuxCPUInfo
:
83 case StreamType::LinuxProcStatus
:
84 case StreamType::LinuxLSBRelease
:
85 case StreamType::LinuxCMDLine
:
86 case StreamType::LinuxMaps
:
87 case StreamType::LinuxProcStat
:
88 case StreamType::LinuxProcUptime
:
89 return StreamKind::TextContent
;
90 case StreamType::ThreadList
:
91 return StreamKind::ThreadList
;
93 return StreamKind::RawContent
;
97 std::unique_ptr
<Stream
> Stream::create(StreamType Type
) {
98 StreamKind Kind
= getKind(Type
);
100 case StreamKind::Exception
:
101 return std::make_unique
<ExceptionStream
>();
102 case StreamKind::MemoryInfoList
:
103 return std::make_unique
<MemoryInfoListStream
>();
104 case StreamKind::MemoryList
:
105 return std::make_unique
<MemoryListStream
>();
106 case StreamKind::ModuleList
:
107 return std::make_unique
<ModuleListStream
>();
108 case StreamKind::RawContent
:
109 return std::make_unique
<RawContentStream
>(Type
);
110 case StreamKind::SystemInfo
:
111 return std::make_unique
<SystemInfoStream
>();
112 case StreamKind::TextContent
:
113 return std::make_unique
<TextContentStream
>(Type
);
114 case StreamKind::ThreadList
:
115 return std::make_unique
<ThreadListStream
>();
117 llvm_unreachable("Unhandled stream kind!");
120 void yaml::ScalarBitSetTraits
<MemoryProtection
>::bitset(
121 IO
&IO
, MemoryProtection
&Protect
) {
122 #define HANDLE_MDMP_PROTECT(CODE, NAME, NATIVENAME) \
123 IO.bitSetCase(Protect, #NATIVENAME, MemoryProtection::NAME);
124 #include "llvm/BinaryFormat/MinidumpConstants.def"
127 void yaml::ScalarBitSetTraits
<MemoryState
>::bitset(IO
&IO
, MemoryState
&State
) {
128 #define HANDLE_MDMP_MEMSTATE(CODE, NAME, NATIVENAME) \
129 IO.bitSetCase(State, #NATIVENAME, MemoryState::NAME);
130 #include "llvm/BinaryFormat/MinidumpConstants.def"
133 void yaml::ScalarBitSetTraits
<MemoryType
>::bitset(IO
&IO
, MemoryType
&Type
) {
134 #define HANDLE_MDMP_MEMTYPE(CODE, NAME, NATIVENAME) \
135 IO.bitSetCase(Type, #NATIVENAME, MemoryType::NAME);
136 #include "llvm/BinaryFormat/MinidumpConstants.def"
139 void yaml::ScalarEnumerationTraits
<ProcessorArchitecture
>::enumeration(
140 IO
&IO
, ProcessorArchitecture
&Arch
) {
141 #define HANDLE_MDMP_ARCH(CODE, NAME) \
142 IO.enumCase(Arch, #NAME, ProcessorArchitecture::NAME);
143 #include "llvm/BinaryFormat/MinidumpConstants.def"
144 IO
.enumFallback
<Hex16
>(Arch
);
147 void yaml::ScalarEnumerationTraits
<OSPlatform
>::enumeration(IO
&IO
,
149 #define HANDLE_MDMP_PLATFORM(CODE, NAME) \
150 IO.enumCase(Plat, #NAME, OSPlatform::NAME);
151 #include "llvm/BinaryFormat/MinidumpConstants.def"
152 IO
.enumFallback
<Hex32
>(Plat
);
155 void yaml::ScalarEnumerationTraits
<StreamType
>::enumeration(IO
&IO
,
157 #define HANDLE_MDMP_STREAM_TYPE(CODE, NAME) \
158 IO.enumCase(Type, #NAME, StreamType::NAME);
159 #include "llvm/BinaryFormat/MinidumpConstants.def"
160 IO
.enumFallback
<Hex32
>(Type
);
163 void yaml::MappingTraits
<CPUInfo::ArmInfo
>::mapping(IO
&IO
,
164 CPUInfo::ArmInfo
&Info
) {
165 mapRequiredHex(IO
, "CPUID", Info
.CPUID
);
166 mapOptionalHex(IO
, "ELF hwcaps", Info
.ElfHWCaps
, 0);
170 template <std::size_t N
> struct FixedSizeHex
{
171 FixedSizeHex(uint8_t (&Storage
)[N
]) : Storage(Storage
) {}
173 uint8_t (&Storage
)[N
];
179 template <std::size_t N
> struct ScalarTraits
<FixedSizeHex
<N
>> {
180 static void output(const FixedSizeHex
<N
> &Fixed
, void *, raw_ostream
&OS
) {
181 OS
<< toHex(makeArrayRef(Fixed
.Storage
));
184 static StringRef
input(StringRef Scalar
, void *, FixedSizeHex
<N
> &Fixed
) {
185 if (!all_of(Scalar
, isHexDigit
))
186 return "Invalid hex digit in input";
187 if (Scalar
.size() < 2 * N
)
188 return "String too short";
189 if (Scalar
.size() > 2 * N
)
190 return "String too long";
191 copy(fromHex(Scalar
), Fixed
.Storage
);
195 static QuotingType
mustQuote(StringRef S
) { return QuotingType::None
; }
199 void yaml::MappingTraits
<CPUInfo::OtherInfo
>::mapping(
200 IO
&IO
, CPUInfo::OtherInfo
&Info
) {
201 FixedSizeHex
<sizeof(Info
.ProcessorFeatures
)> Features(Info
.ProcessorFeatures
);
202 IO
.mapRequired("Features", Features
);
206 /// A type which only accepts strings of a fixed size for yaml conversion.
207 template <std::size_t N
> struct FixedSizeString
{
208 FixedSizeString(char (&Storage
)[N
]) : Storage(Storage
) {}
216 template <std::size_t N
> struct ScalarTraits
<FixedSizeString
<N
>> {
217 static void output(const FixedSizeString
<N
> &Fixed
, void *, raw_ostream
&OS
) {
218 OS
<< StringRef(Fixed
.Storage
, N
);
221 static StringRef
input(StringRef Scalar
, void *, FixedSizeString
<N
> &Fixed
) {
222 if (Scalar
.size() < N
)
223 return "String too short";
224 if (Scalar
.size() > N
)
225 return "String too long";
226 copy(Scalar
, Fixed
.Storage
);
230 static QuotingType
mustQuote(StringRef S
) { return needsQuotes(S
); }
235 void yaml::MappingTraits
<CPUInfo::X86Info
>::mapping(IO
&IO
,
236 CPUInfo::X86Info
&Info
) {
237 FixedSizeString
<sizeof(Info
.VendorID
)> VendorID(Info
.VendorID
);
238 IO
.mapRequired("Vendor ID", VendorID
);
240 mapRequiredHex(IO
, "Version Info", Info
.VersionInfo
);
241 mapRequiredHex(IO
, "Feature Info", Info
.FeatureInfo
);
242 mapOptionalHex(IO
, "AMD Extended Features", Info
.AMDExtendedFeatures
, 0);
245 void yaml::MappingTraits
<MemoryInfo
>::mapping(IO
&IO
, MemoryInfo
&Info
) {
246 mapRequiredHex(IO
, "Base Address", Info
.BaseAddress
);
247 mapOptionalHex(IO
, "Allocation Base", Info
.AllocationBase
, Info
.BaseAddress
);
248 mapRequiredAs
<MemoryProtection
>(IO
, "Allocation Protect",
249 Info
.AllocationProtect
);
250 mapOptionalHex(IO
, "Reserved0", Info
.Reserved0
, 0);
251 mapRequiredHex(IO
, "Region Size", Info
.RegionSize
);
252 mapRequiredAs
<MemoryState
>(IO
, "State", Info
.State
);
253 mapOptionalAs
<MemoryProtection
>(IO
, "Protect", Info
.Protect
,
254 Info
.AllocationProtect
);
255 mapRequiredAs
<MemoryType
>(IO
, "Type", Info
.Type
);
256 mapOptionalHex(IO
, "Reserved1", Info
.Reserved1
, 0);
259 void yaml::MappingTraits
<VSFixedFileInfo
>::mapping(IO
&IO
,
260 VSFixedFileInfo
&Info
) {
261 mapOptionalHex(IO
, "Signature", Info
.Signature
, 0);
262 mapOptionalHex(IO
, "Struct Version", Info
.StructVersion
, 0);
263 mapOptionalHex(IO
, "File Version High", Info
.FileVersionHigh
, 0);
264 mapOptionalHex(IO
, "File Version Low", Info
.FileVersionLow
, 0);
265 mapOptionalHex(IO
, "Product Version High", Info
.ProductVersionHigh
, 0);
266 mapOptionalHex(IO
, "Product Version Low", Info
.ProductVersionLow
, 0);
267 mapOptionalHex(IO
, "File Flags Mask", Info
.FileFlagsMask
, 0);
268 mapOptionalHex(IO
, "File Flags", Info
.FileFlags
, 0);
269 mapOptionalHex(IO
, "File OS", Info
.FileOS
, 0);
270 mapOptionalHex(IO
, "File Type", Info
.FileType
, 0);
271 mapOptionalHex(IO
, "File Subtype", Info
.FileSubtype
, 0);
272 mapOptionalHex(IO
, "File Date High", Info
.FileDateHigh
, 0);
273 mapOptionalHex(IO
, "File Date Low", Info
.FileDateLow
, 0);
276 void yaml::MappingTraits
<ModuleListStream::entry_type
>::mapping(
277 IO
&IO
, ModuleListStream::entry_type
&M
) {
278 mapRequiredHex(IO
, "Base of Image", M
.Entry
.BaseOfImage
);
279 mapRequiredHex(IO
, "Size of Image", M
.Entry
.SizeOfImage
);
280 mapOptionalHex(IO
, "Checksum", M
.Entry
.Checksum
, 0);
281 mapOptional(IO
, "Time Date Stamp", M
.Entry
.TimeDateStamp
, 0);
282 IO
.mapRequired("Module Name", M
.Name
);
283 IO
.mapOptional("Version Info", M
.Entry
.VersionInfo
, VSFixedFileInfo());
284 IO
.mapRequired("CodeView Record", M
.CvRecord
);
285 IO
.mapOptional("Misc Record", M
.MiscRecord
, yaml::BinaryRef());
286 mapOptionalHex(IO
, "Reserved0", M
.Entry
.Reserved0
, 0);
287 mapOptionalHex(IO
, "Reserved1", M
.Entry
.Reserved1
, 0);
290 static void streamMapping(yaml::IO
&IO
, RawContentStream
&Stream
) {
291 IO
.mapOptional("Content", Stream
.Content
);
292 IO
.mapOptional("Size", Stream
.Size
, Stream
.Content
.binary_size());
295 static StringRef
streamValidate(RawContentStream
&Stream
) {
296 if (Stream
.Size
.value
< Stream
.Content
.binary_size())
297 return "Stream size must be greater or equal to the content size";
301 void yaml::MappingTraits
<MemoryListStream::entry_type
>::mapping(
302 IO
&IO
, MemoryListStream::entry_type
&Range
) {
303 MappingContextTraits
<MemoryDescriptor
, yaml::BinaryRef
>::mapping(
304 IO
, Range
.Entry
, Range
.Content
);
307 static void streamMapping(yaml::IO
&IO
, MemoryInfoListStream
&Stream
) {
308 IO
.mapRequired("Memory Ranges", Stream
.Infos
);
311 static void streamMapping(yaml::IO
&IO
, MemoryListStream
&Stream
) {
312 IO
.mapRequired("Memory Ranges", Stream
.Entries
);
315 static void streamMapping(yaml::IO
&IO
, ModuleListStream
&Stream
) {
316 IO
.mapRequired("Modules", Stream
.Entries
);
319 static void streamMapping(yaml::IO
&IO
, SystemInfoStream
&Stream
) {
320 SystemInfo
&Info
= Stream
.Info
;
321 IO
.mapRequired("Processor Arch", Info
.ProcessorArch
);
322 mapOptional(IO
, "Processor Level", Info
.ProcessorLevel
, 0);
323 mapOptional(IO
, "Processor Revision", Info
.ProcessorRevision
, 0);
324 IO
.mapOptional("Number of Processors", Info
.NumberOfProcessors
, 0);
325 IO
.mapOptional("Product type", Info
.ProductType
, 0);
326 mapOptional(IO
, "Major Version", Info
.MajorVersion
, 0);
327 mapOptional(IO
, "Minor Version", Info
.MinorVersion
, 0);
328 mapOptional(IO
, "Build Number", Info
.BuildNumber
, 0);
329 IO
.mapRequired("Platform ID", Info
.PlatformId
);
330 IO
.mapOptional("CSD Version", Stream
.CSDVersion
, "");
331 mapOptionalHex(IO
, "Suite Mask", Info
.SuiteMask
, 0);
332 mapOptionalHex(IO
, "Reserved", Info
.Reserved
, 0);
333 switch (static_cast<ProcessorArchitecture
>(Info
.ProcessorArch
)) {
334 case ProcessorArchitecture::X86
:
335 case ProcessorArchitecture::AMD64
:
336 IO
.mapOptional("CPU", Info
.CPU
.X86
);
338 case ProcessorArchitecture::ARM
:
339 case ProcessorArchitecture::ARM64
:
340 IO
.mapOptional("CPU", Info
.CPU
.Arm
);
343 IO
.mapOptional("CPU", Info
.CPU
.Other
);
348 static void streamMapping(yaml::IO
&IO
, TextContentStream
&Stream
) {
349 IO
.mapOptional("Text", Stream
.Text
);
352 void yaml::MappingContextTraits
<MemoryDescriptor
, yaml::BinaryRef
>::mapping(
353 IO
&IO
, MemoryDescriptor
&Memory
, BinaryRef
&Content
) {
354 mapRequiredHex(IO
, "Start of Memory Range", Memory
.StartOfMemoryRange
);
355 IO
.mapRequired("Content", Content
);
358 void yaml::MappingTraits
<ThreadListStream::entry_type
>::mapping(
359 IO
&IO
, ThreadListStream::entry_type
&T
) {
360 mapRequiredHex(IO
, "Thread Id", T
.Entry
.ThreadId
);
361 mapOptionalHex(IO
, "Suspend Count", T
.Entry
.SuspendCount
, 0);
362 mapOptionalHex(IO
, "Priority Class", T
.Entry
.PriorityClass
, 0);
363 mapOptionalHex(IO
, "Priority", T
.Entry
.Priority
, 0);
364 mapOptionalHex(IO
, "Environment Block", T
.Entry
.EnvironmentBlock
, 0);
365 IO
.mapRequired("Context", T
.Context
);
366 IO
.mapRequired("Stack", T
.Entry
.Stack
, T
.Stack
);
369 static void streamMapping(yaml::IO
&IO
, ThreadListStream
&Stream
) {
370 IO
.mapRequired("Threads", Stream
.Entries
);
373 static void streamMapping(yaml::IO
&IO
, MinidumpYAML::ExceptionStream
&Stream
) {
374 mapRequiredHex(IO
, "Thread ID", Stream
.MDExceptionStream
.ThreadId
);
375 IO
.mapRequired("Exception Record", Stream
.MDExceptionStream
.ExceptionRecord
);
376 IO
.mapRequired("Thread Context", Stream
.ThreadContext
);
379 void yaml::MappingTraits
<minidump::Exception
>::mapping(
380 yaml::IO
&IO
, minidump::Exception
&Exception
) {
381 mapRequiredHex(IO
, "Exception Code", Exception
.ExceptionCode
);
382 mapOptionalHex(IO
, "Exception Flags", Exception
.ExceptionFlags
, 0);
383 mapOptionalHex(IO
, "Exception Record", Exception
.ExceptionRecord
, 0);
384 mapOptionalHex(IO
, "Exception Address", Exception
.ExceptionAddress
, 0);
385 mapOptional(IO
, "Number of Parameters", Exception
.NumberParameters
, 0);
387 for (size_t Index
= 0; Index
< Exception
.MaxParameters
; ++Index
) {
388 SmallString
<16> Name("Parameter ");
389 Twine(Index
).toVector(Name
);
390 support::ulittle64_t
&Field
= Exception
.ExceptionInformation
[Index
];
392 if (Index
< Exception
.NumberParameters
)
393 mapRequiredHex(IO
, Name
.c_str(), Field
);
395 mapOptionalHex(IO
, Name
.c_str(), Field
, 0);
399 void yaml::MappingTraits
<std::unique_ptr
<Stream
>>::mapping(
400 yaml::IO
&IO
, std::unique_ptr
<MinidumpYAML::Stream
> &S
) {
404 IO
.mapRequired("Type", Type
);
406 if (!IO
.outputting())
407 S
= MinidumpYAML::Stream::create(Type
);
409 case MinidumpYAML::Stream::StreamKind::Exception
:
410 streamMapping(IO
, llvm::cast
<MinidumpYAML::ExceptionStream
>(*S
));
412 case MinidumpYAML::Stream::StreamKind::MemoryInfoList
:
413 streamMapping(IO
, llvm::cast
<MemoryInfoListStream
>(*S
));
415 case MinidumpYAML::Stream::StreamKind::MemoryList
:
416 streamMapping(IO
, llvm::cast
<MemoryListStream
>(*S
));
418 case MinidumpYAML::Stream::StreamKind::ModuleList
:
419 streamMapping(IO
, llvm::cast
<ModuleListStream
>(*S
));
421 case MinidumpYAML::Stream::StreamKind::RawContent
:
422 streamMapping(IO
, llvm::cast
<RawContentStream
>(*S
));
424 case MinidumpYAML::Stream::StreamKind::SystemInfo
:
425 streamMapping(IO
, llvm::cast
<SystemInfoStream
>(*S
));
427 case MinidumpYAML::Stream::StreamKind::TextContent
:
428 streamMapping(IO
, llvm::cast
<TextContentStream
>(*S
));
430 case MinidumpYAML::Stream::StreamKind::ThreadList
:
431 streamMapping(IO
, llvm::cast
<ThreadListStream
>(*S
));
436 StringRef
yaml::MappingTraits
<std::unique_ptr
<Stream
>>::validate(
437 yaml::IO
&IO
, std::unique_ptr
<MinidumpYAML::Stream
> &S
) {
439 case MinidumpYAML::Stream::StreamKind::RawContent
:
440 return streamValidate(cast
<RawContentStream
>(*S
));
441 case MinidumpYAML::Stream::StreamKind::Exception
:
442 case MinidumpYAML::Stream::StreamKind::MemoryInfoList
:
443 case MinidumpYAML::Stream::StreamKind::MemoryList
:
444 case MinidumpYAML::Stream::StreamKind::ModuleList
:
445 case MinidumpYAML::Stream::StreamKind::SystemInfo
:
446 case MinidumpYAML::Stream::StreamKind::TextContent
:
447 case MinidumpYAML::Stream::StreamKind::ThreadList
:
450 llvm_unreachable("Fully covered switch above!");
453 void yaml::MappingTraits
<Object
>::mapping(IO
&IO
, Object
&O
) {
454 IO
.mapTag("!minidump", true);
455 mapOptionalHex(IO
, "Signature", O
.Header
.Signature
, Header::MagicSignature
);
456 mapOptionalHex(IO
, "Version", O
.Header
.Version
, Header::MagicVersion
);
457 mapOptionalHex(IO
, "Flags", O
.Header
.Flags
, 0);
458 IO
.mapRequired("Streams", O
.Streams
);
461 Expected
<std::unique_ptr
<Stream
>>
462 Stream::create(const Directory
&StreamDesc
, const object::MinidumpFile
&File
) {
463 StreamKind Kind
= getKind(StreamDesc
.Type
);
465 case StreamKind::Exception
: {
466 Expected
<const minidump::ExceptionStream
&> ExpectedExceptionStream
=
467 File
.getExceptionStream();
468 if (!ExpectedExceptionStream
)
469 return ExpectedExceptionStream
.takeError();
470 Expected
<ArrayRef
<uint8_t>> ExpectedThreadContext
=
471 File
.getRawData(ExpectedExceptionStream
->ThreadContext
);
472 if (!ExpectedThreadContext
)
473 return ExpectedThreadContext
.takeError();
474 return std::make_unique
<ExceptionStream
>(*ExpectedExceptionStream
,
475 *ExpectedThreadContext
);
477 case StreamKind::MemoryInfoList
: {
478 if (auto ExpectedList
= File
.getMemoryInfoList())
479 return std::make_unique
<MemoryInfoListStream
>(*ExpectedList
);
481 return ExpectedList
.takeError();
483 case StreamKind::MemoryList
: {
484 auto ExpectedList
= File
.getMemoryList();
486 return ExpectedList
.takeError();
487 std::vector
<MemoryListStream::entry_type
> Ranges
;
488 for (const MemoryDescriptor
&MD
: *ExpectedList
) {
489 auto ExpectedContent
= File
.getRawData(MD
.Memory
);
490 if (!ExpectedContent
)
491 return ExpectedContent
.takeError();
492 Ranges
.push_back({MD
, *ExpectedContent
});
494 return std::make_unique
<MemoryListStream
>(std::move(Ranges
));
496 case StreamKind::ModuleList
: {
497 auto ExpectedList
= File
.getModuleList();
499 return ExpectedList
.takeError();
500 std::vector
<ModuleListStream::entry_type
> Modules
;
501 for (const Module
&M
: *ExpectedList
) {
502 auto ExpectedName
= File
.getString(M
.ModuleNameRVA
);
504 return ExpectedName
.takeError();
505 auto ExpectedCv
= File
.getRawData(M
.CvRecord
);
507 return ExpectedCv
.takeError();
508 auto ExpectedMisc
= File
.getRawData(M
.MiscRecord
);
510 return ExpectedMisc
.takeError();
512 {M
, std::move(*ExpectedName
), *ExpectedCv
, *ExpectedMisc
});
514 return std::make_unique
<ModuleListStream
>(std::move(Modules
));
516 case StreamKind::RawContent
:
517 return std::make_unique
<RawContentStream
>(StreamDesc
.Type
,
518 File
.getRawStream(StreamDesc
));
519 case StreamKind::SystemInfo
: {
520 auto ExpectedInfo
= File
.getSystemInfo();
522 return ExpectedInfo
.takeError();
523 auto ExpectedCSDVersion
= File
.getString(ExpectedInfo
->CSDVersionRVA
);
524 if (!ExpectedCSDVersion
)
525 return ExpectedInfo
.takeError();
526 return std::make_unique
<SystemInfoStream
>(*ExpectedInfo
,
527 std::move(*ExpectedCSDVersion
));
529 case StreamKind::TextContent
:
530 return std::make_unique
<TextContentStream
>(
531 StreamDesc
.Type
, toStringRef(File
.getRawStream(StreamDesc
)));
532 case StreamKind::ThreadList
: {
533 auto ExpectedList
= File
.getThreadList();
535 return ExpectedList
.takeError();
536 std::vector
<ThreadListStream::entry_type
> Threads
;
537 for (const Thread
&T
: *ExpectedList
) {
538 auto ExpectedStack
= File
.getRawData(T
.Stack
.Memory
);
540 return ExpectedStack
.takeError();
541 auto ExpectedContext
= File
.getRawData(T
.Context
);
542 if (!ExpectedContext
)
543 return ExpectedContext
.takeError();
544 Threads
.push_back({T
, *ExpectedStack
, *ExpectedContext
});
546 return std::make_unique
<ThreadListStream
>(std::move(Threads
));
549 llvm_unreachable("Unhandled stream kind!");
552 Expected
<Object
> Object::create(const object::MinidumpFile
&File
) {
553 std::vector
<std::unique_ptr
<Stream
>> Streams
;
554 Streams
.reserve(File
.streams().size());
555 for (const Directory
&StreamDesc
: File
.streams()) {
556 auto ExpectedStream
= Stream::create(StreamDesc
, File
);
558 return ExpectedStream
.takeError();
559 Streams
.push_back(std::move(*ExpectedStream
));
561 return Object(File
.header(), std::move(Streams
));